56 results available
Sign in
Skills directory

kotlin-mcp-server-generator

github

·

Last changed
Not yet hardened

This version isn't hardened by Chainguard

No hardening report available.


SKILL.md

Kotlin MCP Server Project Generator

Generate a complete, production-ready Model Context Protocol (MCP) server project in Kotlin.

Project Requirements

You will create a Kotlin MCP server with:

  1. Project Structure: Gradle-based Kotlin project layout
  2. Dependencies: Official MCP SDK, Ktor, and kotlinx libraries
  3. Server Setup: Configured MCP server with transports
  4. Tools: At least 2-3 useful tools with typed inputs/outputs
  5. Error Handling: Proper exception handling and validation
  6. Documentation: README with setup and usage instructions
  7. Testing: Basic test structure with coroutines

Template Structure

myserver/
├── build.gradle.kts
├── settings.gradle.kts
├── gradle.properties
├── src/
│   ├── main/
│   │   └── kotlin/
│   │       └── com/example/myserver/
│   │           ├── Main.kt
│   │           ├── Server.kt
│   │           ├── config/
│   │           │   └── Config.kt
│   │           └── tools/
│   │               ├── Tool1.kt
│   │               └── Tool2.kt
│   └── test/
│       └── kotlin/
│           └── com/example/myserver/
│               └── ServerTest.kt
└── README.md

build.gradle.kts Template

plugins {
    kotlin("jvm") version "2.1.0"
    kotlin("plugin.serialization") version "2.1.0"
    application
}

group = "com.example"
version = "1.0.0"

dependencies {
    implementation("io.modelcontextprotocol:kotlin-sdk:0.7.2")
    
    // Ktor for transports
    implementation("io.ktor:ktor-server-netty:3.0.0")
    implementation("io.ktor:ktor-client-cio:3.0.0")
    
    // Serialization
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
    
    // Coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
    
    // Logging
    implementation("org.slf4j:slf4j-api:2.0.16")
    implementation("ch.qos.logback:logback-classic:1.5.12")
    
    // Testing
    testImplementation(kotlin("test"))
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
}

application {
    mainClass.set("com.example.myserver.MainKt")
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain(17)
}

settings.gradle.kts Template

rootProject.name = "{{PROJECT_NAME}}"

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
    }
}

The FAIL_ON_PROJECT_REPOS mode prevents subprojects from adding unvetted repositories.

Main.kt Template

package com.example.myserver

import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
import kotlinx.coroutines.runBlocking
import org.slf4j.LoggerFactory

private val logger = LoggerFactory.getLogger("com.example.myserver.MainKt")

fun main() = runBlocking {
    logger.info("Starting MCP server...")
    
    val config = loadConfig()
    val server = createServer(config)
    
    // Use stdio transport
    val transport = StdioServerTransport()
    
    logger.info("Server '${config.name}' v${config.version} ready")
    server.connect(transport)
}

Server.kt Template

package com.example.myserver

import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.Implementation
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
import com.example.myserver.tools.registerTools

fun createServer(config: Config): Server {
    val server = Server(
        serverInfo = Implementation(
            name = config.name,
            version = config.version
        ),
        options = ServerOptions(
            capabilities = ServerCapabilities(
                tools = ServerCapabilities.Tools(),
                resources = ServerCapabilities.Resources(
                    subscribe = true,
                    listChanged = true
                ),
                prompts = ServerCapabilities.Prompts(listChanged = true)
            )
        )
    ) {
        config.description
    }
    
    // Register all tools
    server.registerTools()
    
    return server
}

Config.kt Template

package com.example.myserver.config

import kotlinx.serialization.Serializable

@Serializable
data class Config(
    val name: String = "{{PROJECT_NAME}}",
    val version: String = "1.0.0",
    val description: String = "{{PROJECT_DESCRIPTION}}"
)

fun loadConfig(): Config {
    return Config(
        name = System.getenv("SERVER_NAME") ?: "{{PROJECT_NAME}}",
        version = System.getenv("VERSION") ?: "1.0.0",
        description = System.getenv("DESCRIPTION") ?: "{{PROJECT_DESCRIPTION}}"
    )
}

Each tool is registered via an explicit named extension function (registerTool1, registerTool2, …) called from ToolRegistry.kt. This pattern makes tool surface area auditable at a glance.

Tool1.kt Template

package com.example.myserver.tools

import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.CallToolRequest
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
import io.modelcontextprotocol.kotlin.sdk.TextContent
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonObject
import kotlinx.serialization.json.putJsonArray

fun Server.registerTool1() {
    addTool(
        name = "tool1",
        description = "Description of what tool1 does",
        inputSchema = buildJsonObject {
            put("type", "object")
            putJsonObject("properties") {
                putJsonObject("param1") {
                    put("type", "string")
                    put("description", "First parameter")
                }
                putJsonObject("param2") {
                    put("type", "integer")
                    put("description", "Optional second parameter")
                }
            }
            putJsonArray("required") {
                add("param1")
            }
        }
    ) { request: CallToolRequest ->
        // Extract and validate parameters
        val param1 = request.params.arguments["param1"] as? String
            ?: throw IllegalArgumentException("param1 is required")
        val param2 = (request.params.arguments["param2"] as? Number)?.toInt() ?: 0
        
        // Perform tool logic
        val result = performTool1Logic(param1, param2)
        
        CallToolResult(
            content = listOf(
                TextContent(text = result)
            )
        )
    }
}

private fun performTool1Logic(param1: String, param2: Int): String {
    // Implement tool logic here
    return "Processed: $param1 with value $param2"
}

tools/Tool2.kt Template

package com.example.myserver.tools

import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.CallToolRequest
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
import io.modelcontextprotocol.kotlin.sdk.TextContent
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonObject
import kotlinx.serialization.json.putJsonArray

fun Server.registerTool2() {
    addTool(
        name = "tool2",
        description = "A simple tool that echoes a message.",
        inputSchema = buildJsonObject {
            put("type", "object")
            putJsonObject("properties") {
                putJsonObject("message") {
                    put("type", "string")
                    put("description", "The message to echo.")
                }
            }
            putJsonArray("required") {
                add("message")
            }
        }
    ) { request: CallToolRequest ->
        val message = request.params.arguments["message"] as? String
            ?: throw IllegalArgumentException("message is required")

        CallToolResult(
            content = listOf(
                TextContent(text = "Tool 2 echoed: $message")
            )
        )
    }
}

tools/ToolRegistry.kt Template

package com.example.myserver.tools

import io.modelcontextprotocol.kotlin.sdk.server.Server

fun Server.registerTools() {
    registerTool1()
    registerTool2()
    // Register additional tools here
}

ServerTest.kt Template

package com.example.myserver

import com.example.myserver.config.Config
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse

class ServerTest {
    
    @Test
    fun `test server creation`() = runTest {
        val config = Config(
            name = "test-server",
            version = "1.0.0",
            description = "Test server"
        )
        
        val server = createServer(config)
        
        assertEquals("test-server", server.serverInfo.name)
        assertEquals("1.0.0", server.serverInfo.version)
    }
    
    @Test
    fun `test tool1 execution`() = runTest {
        val config = Config()
        val server = createServer(config)
        
        // Test tool execution
        // Note: You'll need to implement proper testing utilities
        // for calling tools in the server
    }
}

README.md Template

# {{PROJECT_NAME}}

A Model Context Protocol (MCP) server built with Kotlin.

## Description

{{PROJECT_DESCRIPTION}}

## Requirements

- Java 17 or higher
- Kotlin 2.1.0

## Installation

Build the project:

\`\`\`bash
./gradlew build
\`\`\`

## Usage

Run the server with stdio transport:

\`\`\`bash
./gradlew run
\`\`\`

Or build and run the jar:

\`\`\`bash
./gradlew installDist
./build/install/{{PROJECT_NAME}}/bin/{{PROJECT_NAME}}
\`\`\`

## Configuration

Configure via environment variables:

- `SERVER_NAME`: Server name (default: "{{PROJECT_NAME}}")
- `VERSION`: Server version (default: "1.0.0")
- `DESCRIPTION`: Server description

## Available Tools

### tool1
{{TOOL1_DESCRIPTION}}

**Input:**
- `param1` (string, required): First parameter
- `param2` (integer, optional): Second parameter

**Output:**
- Text result of the operation

## Development

Run tests:

\`\`\`bash
./gradlew test
\`\`\`

Build:

\`\`\`bash
./gradlew build
\`\`\`

Run with auto-reload (development):

\`\`\`bash
./gradlew run --continuous
\`\`\`

## Platform

This project targets the JVM (Java 17+). For multiplatform targets see the
"Multiplatform Configuration" section of the generator documentation.

## Security

This project is configured to resolve dependencies from Maven Central only.
For enhanced supply-chain security, generate and commit Gradle dependency
verification metadata after the first successful build:

\`\`\`bash
./gradlew --write-verification-metadata sha256
\`\`\`

Commit the generated `gradle/verification-metadata.xml` file to your repository.
This ensures Gradle verifies checksums of all dependencies on subsequent builds.

## License

MIT

Generation Instructions

When generating a Kotlin MCP server:

  1. Gradle Setup: Create proper build.gradle.kts with all dependencies
  2. Package Structure: Follow Kotlin package conventions
  3. Type Safety: Use data classes and kotlinx.serialization
  4. Coroutines: All operations should be suspending functions
  5. Error Handling: Use Kotlin exceptions and validation
  6. JSON Schemas: Use buildJsonObject for tool schemas
  7. Testing: Include coroutine test utilities
  8. Logging: Use SLF4J API (org.slf4j:slf4j-api) with Logback as the runtime implementation. After the initial build, run ./gradlew --write-verification-metadata sha256 and commit gradle/verification-metadata.xml to lock dependency checksums.
  9. Configuration: Use data classes and environment variables
  10. Documentation: KDoc comments for public APIs

Best Practices

  • Use suspending functions for all async operations
  • Leverage Kotlin's null safety and type system
  • Use data classes for structured data
  • Apply kotlinx.serialization for JSON handling
  • Use sealed classes for result types
  • Implement proper error handling with Result/Either patterns
  • Write tests using kotlinx-coroutines-test
  • Use dependency injection for testability
  • Follow Kotlin coding conventions
  • Use meaningful names and KDoc comments
  • After scaffolding, run ./gradlew --write-verification-metadata sha256 and commit gradle/verification-metadata.xml to protect against dependency substitution attacks.

Transport Options

Stdio Transport

val transport = StdioServerTransport()
server.connect(transport)

SSE Transport (Ktor)

embeddedServer(Netty, port = 8080) {
    mcp {
        Server(/*...*/) { "Description" }
    }
}.start(wait = true)

Multiplatform Configuration

For multiplatform projects, add to build.gradle.kts:

kotlin {
    jvm()
    js(IR) { nodejs() }
    wasmJs()
    
    sourceSets {
        commonMain.dependencies {
            implementation("io.modelcontextprotocol:kotlin-sdk:0.7.2")
        }
    }
}

Install

Need this version hardened?

Harden your own skills

Bring Chainguard's hardening pipeline to your first-party skills — custom rulesets, automated remediation, full audit trail.

Provenance

Upstream source

—

Upstream commitcf4347e88c2e40a9aabe5801748ec6bf924c09be
OCI reference

—

License

MIT

Files

HARDENING.md

LICENSE

SKILL.md


The trusted source for open source

Talk to an expert
PrivacyTerms

Product

Chainguard ContainersChainguard LibrariesChainguard VMsChainguard OS PackagesChainguard ActionsChainguard Agent SkillsIntegrationsPricing
© 2026 Chainguard, Inc. All Rights Reserved.
Chainguard® and the Chainguard logo are registered trademarks of Chainguard, Inc. in the United States and/or other countries.
The other respective trademarks mentioned on this page are owned by the respective companies and use of them does not imply any affiliation or endorsement.