Skip to content

Commit c11285e

Browse files
authored
Merge pull request #163 from joreilly/backend_mcp
Remote MCP Server
2 parents 89def62 + d8b92f1 commit c11285e

File tree

8 files changed

+48
-38
lines changed

8 files changed

+48
-38
lines changed

.github/workflows/ios.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
java-version: 21
2020

2121
- name: Build iOS app
22-
run: xcodebuild -allowProvisioningUpdates -allowProvisioningUpdates -workspace iosApp/iosApp.xcodeproj/project.xcworkspace -configuration Debug -scheme iosApp -sdk iphoneos -destination name='iPhone 15'
22+
run: xcodebuild -allowProvisioningUpdates -allowProvisioningUpdates -workspace iosApp/iosApp.xcodeproj/project.xcworkspace -configuration Debug -scheme iosApp -sdk iphoneos -destination name='iPhone 16'
2323

2424

2525

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ plugins {
66
alias(libs.plugins.jetbrainsCompose) apply false
77
alias(libs.plugins.kotlinMultiplatform) apply false
88
alias(libs.plugins.kmpNativeCoroutines) apply false
9+
alias(libs.plugins.jib) apply false
910
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GET https://api.climatetrace.org/v6/definitions/countries

composeApp/src/jvmMain/kotlin/dev/johnoreilly/climatetrace/di/Koin.desktop.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dev.johnoreilly.climatetrace.remote.Country
44
import io.github.xxfast.kstore.KStore
55
import io.github.xxfast.kstore.file.storeOf
66
import kotlinx.io.files.Path
7+
import kotlinx.io.files.SystemFileSystem
78
import net.harawata.appdirs.AppDirsFactory
89
import org.koin.core.module.Module
910
import org.koin.dsl.module
@@ -15,7 +16,9 @@ private const val AUTHOR = "johnoreilly"
1516
actual fun dataModule(): Module = module {
1617
single<KStore<List<Country>>> {
1718
val filesDir: String = AppDirsFactory.getInstance()
18-
.getUserDataDir(PACKAGE_NAME, VERSION, AUTHOR)
19+
.getUserCacheDir(PACKAGE_NAME, VERSION, AUTHOR)
20+
val files = Path(filesDir)
21+
with(SystemFileSystem) { if(!exists(files)) createDirectories(files) }
1922
storeOf(file = Path(path = "$filesDir/countries.json"), default = emptyList())
2023
}
2124
}

gradle/libs.versions.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
kotlin = "2.2.0"
33
ksp = "2.2.0-2.0.2"
44
kotlinx-coroutines = "1.10.2"
5-
5+
kotlinxSerialization = "1.9.0"
66

77
agp = "8.11.1"
88
android-compileSdk = "36"
@@ -24,8 +24,8 @@ treemapChart = "0.1.3"
2424
voyager= "1.1.0-beta03"
2525
molecule = "2.1.0"
2626
mcp = "0.6.0"
27-
shadowPlugin = "8.1.1"
28-
27+
shadowPlugin = "9.0.0-rc2"
28+
jib = "3.4.5"
2929

3030
[libraries]
3131
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
@@ -41,6 +41,7 @@ koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
4141

4242

4343
kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
44+
kotlinx-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinxSerialization" }
4445
kmpObservableViewModel = { module = "com.rickclephas.kmp:kmp-observableviewmodel-core", version.ref = "kmpObservableViewModel" }
4546

4647
kstore = { module = "io.github.xxfast:kstore", version.ref = "kstore" }
@@ -80,4 +81,7 @@ kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", vers
8081
kmpNativeCoroutines = { id = "com.rickclephas.kmp.nativecoroutines", version.ref = "kmpNativeCoroutines" }
8182
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
8283
kotlinJvm = { id = "org.jetbrains.kotlin.jvm" }
83-
shadowPlugin = { id = "com.github.johnrengelman.shadow", version.ref = "shadowPlugin" }
84+
shadowPlugin = { id = "com.gradleup.shadow", version.ref = "shadowPlugin" }
85+
jib = { id = "com.google.cloud.tools.jib", version.ref = "jib" }
86+
87+

mcp-server/build.gradle.kts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ plugins {
22
alias(libs.plugins.kotlinJvm)
33
alias(libs.plugins.kotlinx.serialization)
44
alias(libs.plugins.shadowPlugin)
5+
alias(libs.plugins.jib)
56
application
67
}
78

89
dependencies {
910
implementation(libs.mcp.kotlin)
1011
implementation(libs.koin.core)
12+
implementation("ch.qos.logback:logback-classic:1.5.8")
1113
implementation(projects.composeApp)
1214
}
1315

@@ -18,14 +20,25 @@ java {
1820
}
1921

2022
application {
21-
mainClass = "MainKt"
23+
mainClass = "McpServerKt"
2224
}
2325

2426
tasks.shadowJar {
2527
archiveFileName.set("serverAll.jar")
2628
archiveClassifier.set("")
2729
manifest {
28-
attributes["Main-Class"] = "MainKt"
30+
attributes["Main-Class"] = "McpServerKt"
2931
}
3032
}
3133

34+
jib {
35+
from.image = "docker.io/library/eclipse-temurin:21"
36+
37+
to {
38+
image = "gcr.io/climatetrace-mcp/climatetrace-mcp-server"
39+
}
40+
container {
41+
ports = listOf("8080")
42+
mainClass = "McpServerKt"
43+
}
44+
}

mcp-server/src/main/kotlin/server.kt renamed to mcp-server/src/main/kotlin/McpServer.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,31 @@ import kotlinx.coroutines.Job
99
import kotlinx.coroutines.runBlocking
1010
import kotlinx.io.asSink
1111
import kotlinx.io.buffered
12-
import kotlinx.serialization.json.JsonObject
1312
import kotlinx.serialization.json.JsonPrimitive
1413
import kotlinx.serialization.json.buildJsonObject
1514
import kotlinx.serialization.json.jsonArray
1615
import kotlinx.serialization.json.jsonPrimitive
1716
import kotlinx.serialization.json.putJsonObject
1817

1918

19+
20+
21+
fun main(args: Array<String>) {
22+
val command = args.firstOrNull() ?: "--sse-server"
23+
val port = args.getOrNull(1)?.toIntOrNull() ?: 8080
24+
when (command) {
25+
"--sse-server" -> `run sse mcp server`(port)
26+
"--stdio" -> `run mcp server using stdio`()
27+
else -> {
28+
System.err.println("Unknown command: $command")
29+
}
30+
}
31+
}
32+
33+
2034
private val koin = initKoin(enableNetworkLogs = true).koin
2135

22-
fun configureServer(): Server {
36+
fun configureMcpServer(): Server {
2337
val climateTraceRepository = koin.get<ClimateTraceRepository>()
2438

2539
val server = Server(
@@ -34,7 +48,6 @@ fun configureServer(): Server {
3448
)
3549
)
3650

37-
3851
server.addTool(
3952
name = "get-countries",
4053
description = "List of countries"
@@ -68,7 +81,6 @@ fun configureServer(): Server {
6881
content = listOf(TextContent("The 'countryCodeList' parameters are required."))
6982
)
7083
}
71-
7284
val countryAssetEmissionInfo = climateTraceRepository.fetchCountryAssetEmissionsInfo(
7385
countryCodeList = countryCodeList
7486
.jsonArray
@@ -130,7 +142,7 @@ fun configureServer(): Server {
130142
* a close event.
131143
*/
132144
fun `run mcp server using stdio`() {
133-
val server = configureServer()
145+
val server = configureMcpServer()
134146
val transport = StdioServerTransport(
135147
System.`in`.asInput(),
136148
System.out.asSink().buffered()
@@ -154,7 +166,7 @@ fun `run mcp server using stdio`() {
154166
* @param port The port number on which the SSE server should be started.
155167
*/
156168
fun `run sse mcp server`(port: Int): Unit = runBlocking {
157-
val server = configureServer()
169+
val server = configureMcpServer()
158170
embeddedServer(CIO, host = "0.0.0.0", port = port) {
159171
mcp {
160172
server

mcp-server/src/main/kotlin/main.kt

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)