Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 42 additions & 13 deletions agents/src/main/kotlin/adk/adk_agent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import com.google.adk.agents.LlmAgent
import com.google.adk.events.Event
import com.google.adk.models.Gemini
import com.google.adk.runner.InMemoryRunner
import com.google.adk.tools.AgentTool
import com.google.adk.tools.BaseTool
import com.google.adk.tools.GoogleSearchTool
import com.google.adk.tools.LongRunningFunctionTool
import com.google.adk.tools.mcp.McpToolset
import com.google.genai.Client
Expand All @@ -26,30 +29,56 @@ class ClimateTraceAgent {
fun initAgent(): BaseAgent {
val apiKeyGoogle = ""

// val mcpTools = McpToolset(
// ServerParameters
// .builder("java")
// .args("-jar", "/Users/joreilly/dev/github/ClimateTraceKMP/mcp-server/build/libs/serverAll.jar", "--stdio")
// .build()
// ).loadTools().join()
val climateTools = McpToolset(
ServerParameters
.builder("java")
.args("-jar", "/Users/joreilly/dev/github/ClimateTraceKMP/mcp-server/build/libs/serverAll.jar", "--stdio")
.build()
).loadTools().join()

// val getCountriesTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getCountries")
// val getEmissionsTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getEmissions")
// val climateTools = listOf(getCountriesTool, getEmissionsTool, GoogleSearchTool())

val getCountriesTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getCountries")
val getEmissionsTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getEmissions")
val mcpTools = listOf(getCountriesTool, getEmissionsTool)

val model = Gemini(
"gemini-1.5-pro",
"gemini-2.0-flash",
Client.builder()
.apiKey(apiKeyGoogle)
.build()
)

return LlmAgent.builder()
.name(NAME)

val searchAgent = LlmAgent.builder()
.name("SearchAgent")
.model(model)
.description("Google Search agent")
.instruction("You're a specialist in Google Search")
.tools(GoogleSearchTool())
.build()

val climateAgent = LlmAgent.builder()
.name("ClimateAgent")
.model(model)
.description("Agent to answer climate emissions related questions.")
.instruction("You are an agent that provides climate emissions related information. Use 3 letter country codes.")
.tools(mcpTools)
.tools(climateTools)
.build()

return LlmAgent.builder()
.name(NAME)
.description("Agent to answer climate emissions related questions.")
//.instruction("You are an agent that provides climate emissions related information. Use 3 letter country codes. Use SearchAgent for population data.")
.instruction("""
You are an agent that provides climate emissions related information.

Use `ClimateAgent` for emission data.
Use `SearchAgent` for population data.
""")

.model(model)
//.subAgents(searchAgent, climateAgent)
.tools(AgentTool.create(searchAgent), AgentTool.create(climateAgent))
.build()
}
}
Expand Down
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
62 changes: 62 additions & 0 deletions backend/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)

import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

plugins {
kotlin("multiplatform")
alias(libs.plugins.kotlinx.serialization)
alias(libs.plugins.shadowPlugin)
alias(libs.plugins.jib)
}

kotlin {
jvm() {
withJava()
binaries {
executable {
mainClass.set("ServerKt")
}
}
}

sourceSets {
jvmMain.dependencies {
implementation(libs.kotlinx.coroutines)
implementation(libs.kotlinx.serialization)

implementation("io.ktor:ktor-server-core:3.2.1")
implementation("io.ktor:ktor-server-netty:3.2.1")
implementation("io.ktor:ktor-server-cors:3.2.1")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.2.1")
implementation("io.ktor:ktor-server-content-negotiation:3.2.1")

implementation("ch.qos.logback:logback-classic:1.5.8")

//implementation(projects.composeApp)
implementation(libs.mcp.kotlin)
implementation(projects.mcpServer)
}
}
}

tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
manifest {
attributes["Main-Class"] = "ServerKt"
}
}

tasks.withType<Tar> { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
tasks.withType<Zip> { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }


jib {
from.image = "docker.io/library/eclipse-temurin:21"

to {
image = "gcr.io/climatetrace-mcp/climatetrace-mcp-server"
}
container {
ports = listOf("8080")
mainClass = "ServerKt"
}
}
30 changes: 30 additions & 0 deletions backend/src/jvmMain/kotlin/Server.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import io.ktor.server.application.*
import io.ktor.server.cio.CIO
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.respond
import io.ktor.server.routing.*
import io.ktor.server.sse.SSE
import io.modelcontextprotocol.kotlin.sdk.server.mcp



fun main() {
val server = configureMcpServer()

val port = System.getenv().getOrDefault("PORT", "8080").toInt()
embeddedServer(CIO, port, host = "0.0.0.0") {
install(SSE)

routing {
mcp {
server
}

get("/hi") {
call.respond("hello!!")

}
}
}.start(wait = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ class ClimateTraceRepository(
private val api: ClimateTraceApi
) {
suspend fun fetchCountries() : List<Country> {
val countries: List<Country>? = store.get()
if (countries.isNullOrEmpty()) return api.fetchCountries().also { store.set(it) }
return countries
// val countries: List<Country>? = store.get()
// if (countries.isNullOrEmpty()) return api.fetchCountries().also { store.set(it) }
// return countries
return api.fetchCountries()
}

suspend fun fetchCountryEmissionsInfo(countryCode: String, year: String) = api.fetchCountryEmissionsInfo(listOf(countryCode), year)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ import io.ktor.client.request.get
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Represents the result of an API call to fetch assets.
* @property assets A list of [Asset] objects.
*/
@Serializable
data class AssetsResult(val assets: List<Asset>)

/**
* Represents a single asset.
* @property id The unique identifier of the asset.
* @property name The name of the asset.
* @property assetType The type of the asset.
* @property sector The sector to which the asset belongs.
* @property thumbnail A URL to a thumbnail image for the asset.
*/
@Serializable
data class Asset(
@SerialName("Id")
Expand Down
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ kmpNativeCoroutines = "1.0.0-ALPHA-45"
kmpObservableViewModel = "1.0.0-BETA-12"
kstore = "1.0.0"
ktor = "3.2.2"
logbackClassic = "1.5.18"
treemapChart = "0.1.3"
voyager= "1.1.0-beta03"
molecule = "2.1.0"
Expand Down Expand Up @@ -58,6 +59,7 @@ ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version
ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" }
ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktor" }

logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logbackClassic" }
voyager = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
harawata-appdirs = { module = "net.harawata:appdirs", version.ref = "harawata-appdirs" }
koalaplot = { module = "io.github.koalaplot:koalaplot-core", version.ref = "koalaplot" }
Expand All @@ -81,6 +83,7 @@ kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", vers
kmpNativeCoroutines = { id = "com.rickclephas.kmp.nativecoroutines", version.ref = "kmpNativeCoroutines" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
kotlinJvm = { id = "org.jetbrains.kotlin.jvm" }
graalvm = { id = "org.graalvm.buildtools.native", version = "0.11.0" }
shadowPlugin = { id = "com.gradleup.shadow", version.ref = "shadowPlugin" }
jib = { id = "com.google.cloud.tools.jib", version.ref = "jib" }

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
version = "1.3">
<BuildAction>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForRunning = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
Expand All @@ -21,25 +15,11 @@
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
Expand All @@ -49,18 +29,4 @@
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
49 changes: 39 additions & 10 deletions mcp-server/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,44 +1,73 @@
@file:Suppress("UnstableApiUsage")

import com.google.cloud.tools.jib.gradle.JibTask


plugins {
alias(libs.plugins.kotlinJvm)
alias(libs.plugins.kotlinx.serialization)
alias(libs.plugins.shadowPlugin)
alias(libs.plugins.jib)
application
alias(libs.plugins.graalvm)
}

dependencies {
implementation(libs.mcp.kotlin)
implementation(libs.koin.core)
implementation("ch.qos.logback:logback-classic:1.5.8")
implementation(projects.composeApp)
implementation(libs.logback.classic)
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
languageVersion.set(JavaLanguageVersion.of(24))
}
}

application {
mainClass = "McpServerKt"
}

tasks.shadowJar {
archiveFileName.set("serverAll.jar")
archiveClassifier.set("")
manifest {
attributes["Main-Class"] = "McpServerKt"
graalvmNative {
agent {
enabled.set(true)
}

binaries {
all {
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(24))
nativeImageCapable.set(true)
})
buildArgs("--enable-url-protocols=http,https")
}
named("main") {
imageName.set("climate-trace-mcp")
mainClass.set("McpServerKt")
}
}
}

jib {
from.image = "docker.io/library/eclipse-temurin:21"
from.image = "docker.io/library/alpine:3.22"

to {
image = "gcr.io/climatetrace-mcp/climatetrace-mcp-server"
}
container {
ports = listOf("8080")
mainClass = "McpServerKt"
entrypoint = listOf("/climate-trace-mcp")
}
extraDirectories {
paths {
path {
setFrom("build/native/nativeCompile")
into = "/"
}
}
}
}

tasks.withType<JibTask> {
dependsOn(tasks.named("nativeCompile"))
}
Loading