Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
32df4dd
Introduce Kotlin integration tests
skarpovdev Jul 22, 2025
39ccebe
Bump org.jetbrains.kotlinx.binary-compatibility-validator (#148)
dependabot[bot] Jul 23, 2025
0f65045
Add optional title property for tool object (#191) (#192)
sdubov Jul 23, 2025
36746f6
Update PR validation workflow (#177)
devcrocod Jul 24, 2025
9be5a14
Update notification schema and refactor tests package structure (#199)
devcrocod Jul 28, 2025
ef35bed
Bump io.mockk:mockk from 1.14.4 to 1.14.5 (#204)
dependabot[bot] Jul 29, 2025
150ed87
Bump protocol version to `2025-03-26` and remove outdated test file (…
devcrocod Jul 29, 2025
7bc826b
Bump ktor from 3.2.1 to 3.2.2 (#205)
dependabot[bot] Jul 29, 2025
759754d
Add CodeQL workflow for Kotlin analysis (#200)
devcrocod Jul 30, 2025
a895a29
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
1c55369
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
99383ae
modularize sdk (#208)
devcrocod Aug 4, 2025
a8c193e
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
b8b0406
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
c75b799
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
2d1887e
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
b6472d4
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
9c45ca7
fixup! Introduce Kotlin integration tests
skarpovdev Aug 4, 2025
d977a5c
Refactor `SseIntegrationTest` to use dynamic port assignment and simp…
devcrocod Aug 4, 2025
26b20b6
fixup! Introduce Kotlin integration tests
skarpovdev Aug 5, 2025
c24c6d9
Add ServerSSESession as a receiver for mcp {} dsl (#190)
nerzhulart Aug 4, 2025
47cbec1
Resolve conflicting publisher settings (#201)
devcrocod Aug 5, 2025
e2a70a9
Fix incorrect deserializer mapping for tool and prompt list notificat…
devcrocod Aug 5, 2025
54d8b17
fixup! Introduce Kotlin integration tests
skarpovdev Aug 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: "CodeQL Advanced"

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '0 4 * * 0'

jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read

strategy:
matrix:
language: [ java-kotlin ]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: manual

- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}

- name: Build Kotlin sources
run: |
./gradlew \
:kotlin-sdk-core:compileKotlinJvm \
:kotlin-sdk-client:compileKotlinJvm \
:kotlin-sdk-server:compileKotlinJvm \
:kotlin-sdk:compileKotlinJvm \
:kotlin-sdk-test:compileKotlinJvm \
-Pkotlin.incremental=false \
--no-daemon --stacktrace

- name: Analyze
uses: github/codeql-action/analyze@v3
with:
category: '/language:${{ matrix.language }}'
8 changes: 6 additions & 2 deletions .github/workflows/validate-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ name: Validate PR
on:
workflow_dispatch:
pull_request:
types: [auto_merge_enabled]
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
validate-pr:
Expand All @@ -17,7 +21,7 @@ jobs:
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4

- name: Clean Build with Gradle
run: ./gradlew clean build
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ bin/
### Node.js ###
node_modules
dist

### SWE agents ###
.claude/
.junie/
282 changes: 4 additions & 278 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,278 +1,4 @@
@file:OptIn(ExperimentalWasmDsl::class)

import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jreleaser.model.Active

plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.atomicfu)
alias(libs.plugins.dokka)
alias(libs.plugins.jreleaser)
`maven-publish`
signing
alias(libs.plugins.kotlinx.binary.compatibility.validator)
}

group = "io.modelcontextprotocol"
version = "0.6.0"

val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}

publishing {
publications.withType(MavenPublication::class).all {
if (name.contains("jvm", ignoreCase = true)) {
artifact(javadocJar)
}
pom.configureMavenCentralMetadata()
signPublicationIfKeyPresent()
}

repositories {
maven(url = layout.buildDirectory.dir("staging-deploy"))
}
}

jreleaser {
gitRootSearch = true
strict = true

signing {
active = Active.ALWAYS
armored = true
artifacts = true
files = true
}

deploy {
active.set(Active.ALWAYS)
maven {
active.set(Active.ALWAYS)
mavenCentral {
val ossrh by creating {
active.set(Active.ALWAYS)
url.set("https://central.sonatype.com/api/v1/publisher")
applyMavenCentralRules = false
maxRetries = 240
stagingRepository(layout.buildDirectory.dir("staging-deploy").get().asFile.path)
// workaround: https://github.com/jreleaser/jreleaser/issues/1784
afterEvaluate {
publishing.publications.forEach { publication ->
if (publication is MavenPublication) {
val pubName = publication.name

if (!pubName.contains("jvm", ignoreCase = true)
&& !pubName.contains("metadata", ignoreCase = true)
&& !pubName.contains("kotlinMultiplatform", ignoreCase = true)
) {

artifactOverride {
artifactId = when {
pubName.contains("wasm", ignoreCase = true) ->
"${project.name}-wasm-${pubName.lowercase().substringAfter("wasm")}"

else -> "${project.name}-${pubName.lowercase()}"
}
jar = false
verifyPom = false
sourceJar = false
javadocJar = false
}
}
}
}
}
}
}
}
}

release {
github {
changelog.enabled = false
skipRelease = true
skipTag = true
overwrite = false
token = "none"
}
}

checksum {
individual = false
artifacts = false
files = false
}
}

fun MavenPom.configureMavenCentralMetadata() {
name by project.name
description by "Kotlin implementation of the Model Context Protocol (MCP)"
url by "https://github.com/modelcontextprotocol/kotlin-sdk"

licenses {
license {
name by "MIT License"
url by "https://github.com/modelcontextprotocol/kotlin-sdk/blob/main/LICENSE"
distribution by "repo"
}
}

developers {
developer {
id by "Anthropic"
name by "Anthropic Team"
organization by "Anthropic"
organizationUrl by "https://www.anthropic.com"
}
}

scm {
url by "https://github.com/modelcontextprotocol/kotlin-sdk"
connection by "scm:git:git://github.com/modelcontextprotocol/kotlin-sdk.git"
developerConnection by "scm:git:[email protected]:modelcontextprotocol/kotlin-sdk.git"
}
}

fun MavenPublication.signPublicationIfKeyPresent() {
val signingKey = project.getSensitiveProperty("GPG_SECRET_KEY")
val signingKeyPassphrase = project.getSensitiveProperty("SIGNING_PASSPHRASE")

if (!signingKey.isNullOrBlank()) {
the<SigningExtension>().apply {
useInMemoryPgpKeys(signingKey, signingKeyPassphrase)

sign(this@signPublicationIfKeyPresent)
}
}
}

fun Project.getSensitiveProperty(name: String?): String? {
if (name == null) {
error("Expected not null property '$name' for publication repository config")
}

return project.findProperty(name) as? String
?: System.getenv(name)
?: System.getProperty(name)
}

infix fun <T> Property<T>.by(value: T) {
set(value)
}

tasks.withType<Test>().configureEach {
useJUnitPlatform()
}

abstract class GenerateLibVersionTask @Inject constructor(
@get:Input val libVersion: String,
@get:OutputDirectory val sourcesDir: File,
) : DefaultTask() {
@TaskAction
fun generate() {
val sourceFile = File(sourcesDir.resolve("io/modelcontextprotocol/kotlin/sdk"), "LibVersion.kt")

if (!sourceFile.exists()) {
sourceFile.parentFile.mkdirs()
sourceFile.createNewFile()
}

sourceFile.writeText(
"""
package io.modelcontextprotocol.kotlin.sdk

public const val LIB_VERSION: String = "$libVersion"

""".trimIndent()
)
}
}

dokka {
moduleName.set("MCP Kotlin SDK")

dokkaSourceSets.configureEach {
sourceLink {
localDirectory.set(file("src/main/kotlin"))
remoteUrl("https://github.com/modelcontextprotocol/kotlin-sdk")
remoteLineSuffix.set("#L")
documentedVisibilities(VisibilityModifier.Public)
}
}
dokkaPublications.html {
outputDirectory.set(project.layout.projectDirectory.dir("docs"))
}
}

val sourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/libVersion")

val generateLibVersionTask =
tasks.register<GenerateLibVersionTask>("generateLibVersion", version.toString(), sourcesDir)

kotlin {
jvm {
compilerOptions {
jvmTarget = JvmTarget.JVM_1_8
}
}

iosArm64()
iosX64()
iosSimulatorArm64()

js(IR) {
nodejs {
testTask {
useMocha {
timeout = "30s"
}
}
}
}

wasmJs {
nodejs()
}

explicitApi = ExplicitApiMode.Strict

jvmToolchain(21)

sourceSets {
commonMain {
kotlin.srcDir(generateLibVersionTask.map { it.sourcesDir })
dependencies {
api(libs.kotlinx.serialization.json)
api(libs.kotlinx.collections.immutable)
api(libs.ktor.client.cio)
api(libs.ktor.server.cio)
api(libs.ktor.server.sse)
api(libs.ktor.server.websockets)

implementation(libs.kotlin.logging)
}
}

commonTest {
dependencies {
implementation(libs.kotlin.test)
implementation(libs.ktor.server.test.host)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.kotest.assertions.json)
}
}

jvmTest {
dependencies {
implementation(libs.ktor.client.mock)
implementation(libs.mockk)
implementation(libs.slf4j.simple)
}
}
}
}
allprojects {
group = "io.modelcontextprotocol"
version = "0.6.0"
}
16 changes: 16 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
`kotlin-dsl`
}

repositories {
gradlePluginPortal()
mavenCentral()
}

dependencies {
implementation(libs.kotlin.gradle)
implementation(libs.kotlin.serialization)
implementation(libs.kotlinx.atomicfu.gradle)
implementation(libs.dokka.gradle)
implementation(libs.jreleaser.gradle)
}
Loading