diff --git a/agents/src/main/kotlin/adk/adk_agent.kt b/agents/src/main/kotlin/adk/adk_agent.kt index d368ff2..36ce9f3 100644 --- a/agents/src/main/kotlin/adk/adk_agent.kt +++ b/agents/src/main/kotlin/adk/adk_agent.kt @@ -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 @@ -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() } } diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts new file mode 100644 index 0000000..9d967d9 --- /dev/null +++ b/backend/build.gradle.kts @@ -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("shadowJar") { + manifest { + attributes["Main-Class"] = "ServerKt" + } +} + +tasks.withType { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } +tasks.withType { 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" + } +} \ No newline at end of file diff --git a/backend/src/jvmMain/kotlin/Server.kt b/backend/src/jvmMain/kotlin/Server.kt new file mode 100644 index 0000000..3d68d82 --- /dev/null +++ b/backend/src/jvmMain/kotlin/Server.kt @@ -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) +} diff --git a/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/data/ClimateTraceRepository.kt b/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/data/ClimateTraceRepository.kt index 18721cf..8313769 100644 --- a/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/data/ClimateTraceRepository.kt +++ b/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/data/ClimateTraceRepository.kt @@ -10,9 +10,10 @@ class ClimateTraceRepository( private val api: ClimateTraceApi ) { suspend fun fetchCountries() : List { - val countries: List? = store.get() - if (countries.isNullOrEmpty()) return api.fetchCountries().also { store.set(it) } - return countries +// val countries: List? = 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) diff --git a/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/remote/ClimateTraceApi.kt b/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/remote/ClimateTraceApi.kt index 61c7e27..48e914c 100644 --- a/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/remote/ClimateTraceApi.kt +++ b/composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/remote/ClimateTraceApi.kt @@ -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) +/** + * 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") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eda77c9..33e21a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" @@ -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" } @@ -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" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b..d4081da 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/iosApp/iosApp.xcodeproj/xcuserdata/joreilly.xcuserdatad/xcschemes/iosApp.xcscheme b/iosApp/iosApp.xcodeproj/xcuserdata/joreilly.xcuserdatad/xcschemes/iosApp.xcscheme index d7bc3b2..b655292 100644 --- a/iosApp/iosApp.xcodeproj/xcuserdata/joreilly.xcuserdatad/xcschemes/iosApp.xcscheme +++ b/iosApp/iosApp.xcodeproj/xcuserdata/joreilly.xcuserdatad/xcschemes/iosApp.xcscheme @@ -1,16 +1,10 @@ - + version = "1.3"> + + buildForRunning = "YES"> - - - + - - - - - - diff --git a/mcp-server/build.gradle.kts b/mcp-server/build.gradle.kts index ecd36eb..db543a5 100644 --- a/mcp-server/build.gradle.kts +++ b/mcp-server/build.gradle.kts @@ -1,21 +1,26 @@ +@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)) } } @@ -23,22 +28,46 @@ 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 { + dependsOn(tasks.named("nativeCompile")) +} diff --git a/mcp-server/src/main/resources/META-INF/native-image/climatetrace/reachability-metadata.json b/mcp-server/src/main/resources/META-INF/native-image/climatetrace/reachability-metadata.json new file mode 100644 index 0000000..71f463e --- /dev/null +++ b/mcp-server/src/main/resources/META-INF/native-image/climatetrace/reachability-metadata.json @@ -0,0 +1,1418 @@ +{ + "reflection": [ + { + "type": "[Lio.ktor.network.selector.SelectInterest;" + }, + { + "type": "[Ljava.lang.Object;" + }, + { + "type": "ch.qos.logback.classic.BasicConfigurator", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "ch.qos.logback.classic.joran.SerializedModelConfigurator", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "ch.qos.logback.classic.spi.LogbackServiceProvider" + }, + { + "type": "ch.qos.logback.classic.util.DefaultJoranConfigurator", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.AESCipher$General", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.ARCFOURCipher", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.ChaCha20Cipher$ChaCha20Poly1305", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.DESCipher", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.DESedeCipher", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.DHParameters", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.GaloisCounterMode$AESGCM", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.HmacCore$HmacSHA256", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "com.sun.crypto.provider.TlsMasterSecretGenerator", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.Country", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.Country$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.CountryAssetEmissionsInfo", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.CountryAssetEmissionsInfo$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.CountryEmissionsInfo", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "dev.johnoreilly.climatetrace.remote.CountryEmissionsInfo$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.ktor.client.HttpClient", + "fields": [ + { + "name": "closed" + } + ] + }, + { + "type": "io.ktor.client.HttpClientConfig" + }, + { + "type": "io.ktor.client.call.HttpClientCall", + "fields": [ + { + "name": "received" + } + ] + }, + { + "type": "io.ktor.client.content.ProgressListener" + }, + { + "type": "io.ktor.client.engine.HttpClientEngineBase", + "fields": [ + { + "name": "closed" + } + ] + }, + { + "type": "io.ktor.client.engine.HttpClientEngineCapability" + }, + { + "type": "io.ktor.client.engine.HttpClientEngineConfig" + }, + { + "type": "io.ktor.client.engine.java.JavaHttpEngineContainer" + }, + { + "type": "io.ktor.client.engine.java.JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", + "fields": [ + { + "name": "closed" + }, + { + "name": "subscription" + } + ] + }, + { + "type": "io.ktor.client.plugins.HttpSend" + }, + { + "type": "io.ktor.client.plugins.api.ClientPluginImpl" + }, + { + "type": "io.ktor.client.plugins.api.ClientPluginInstance" + }, + { + "type": "io.ktor.client.plugins.logging.HttpClientCallLogger", + "fields": [ + { + "name": "requestLogged" + }, + { + "name": "responseLogged" + } + ] + }, + { + "type": "io.ktor.client.request.ResponseAdapter" + }, + { + "type": "io.ktor.http.ContentType" + }, + { + "type": "io.ktor.http.HttpStatusCode" + }, + { + "type": "io.ktor.http.content.TextContent" + }, + { + "type": "io.ktor.network.selector.InterestSuspensionsMap", + "fields": [ + { + "name": "acceptHandlerReference" + }, + { + "name": "connectHandlerReference" + }, + { + "name": "readHandlerReference" + }, + { + "name": "writeHandlerReference" + } + ] + }, + { + "type": "io.ktor.network.selector.LockFreeMPSCQueue", + "fields": [ + { + "name": "curRef" + } + ] + }, + { + "type": "io.ktor.network.selector.LockFreeMPSCQueueCore", + "fields": [ + { + "name": "nextRef" + }, + { + "name": "stateRef" + } + ] + }, + { + "type": "io.ktor.network.selector.SelectableBase", + "fields": [ + { + "name": "_interestedOps" + } + ] + }, + { + "type": "io.ktor.network.sockets.SocketBase", + "fields": [ + { + "name": "actualCloseFlag" + }, + { + "name": "closeFlag" + }, + { + "name": "readerJob" + }, + { + "name": "writerJob" + } + ] + }, + { + "type": "io.ktor.serialization.kotlinx.json.KotlinxSerializationJsonExtensionProvider" + }, + { + "type": "io.ktor.server.application.PluginInstance" + }, + { + "type": "io.ktor.server.engine.BaseApplicationResponse" + }, + { + "type": "io.ktor.server.plugins.MutableOriginConnectionPoint" + }, + { + "type": "io.ktor.server.request.DoubleReceivePreventionToken" + }, + { + "type": "io.ktor.server.routing.RoutingCall" + }, + { + "type": "io.ktor.server.routing.RoutingRoot" + }, + { + "type": "io.ktor.server.sse.SSEServerContent" + }, + { + "type": "io.ktor.util.Attributes" + }, + { + "type": "io.ktor.util.collections.CopyOnWriteHashMap", + "fields": [ + { + "name": "current" + } + ] + }, + { + "type": "io.ktor.util.internal.LockFreeLinkedListNode", + "fields": [ + { + "name": "_next" + }, + { + "name": "_prev" + }, + { + "name": "removedRef" + } + ] + }, + { + "type": "io.ktor.util.reflect.TypeInfo" + }, + { + "type": "io.ktor.utils.io.ByteChannel", + "fields": [ + { + "name": "_closedCause" + }, + { + "name": "suspensionSlot" + } + ] + }, + { + "type": "io.ktor.utils.io.ByteReadChannel" + }, + { + "type": "io.ktor.utils.io.pool.DefaultPool", + "fields": [ + { + "name": "top" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.CallToolRequest", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.CallToolRequest$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.CallToolResult", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.CallToolResult$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.InitializeRequest", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.InitializeRequest$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.InitializeResult", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.InitializeResult$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.JSONRPCResponse", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.JSONRPCResponse$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.ListToolsRequest", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.ListToolsRequest$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.PingRequest", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.PingRequest$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.TextContent", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.TextContent$Companion", + "methods": [ + { + "name": "serializer", + "parameterTypes": [] + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.server.Server", + "fields": [ + { + "name": "_prompts" + }, + { + "name": "_resources" + }, + { + "name": "_tools" + } + ] + }, + { + "type": "io.modelcontextprotocol.kotlin.sdk.shared.Protocol", + "fields": [ + { + "name": "_notificationHandlers" + }, + { + "name": "_progressHandlers" + }, + { + "name": "_requestHandlers" + }, + { + "name": "_responseHandlers" + } + ] + }, + { + "type": "java.lang.Boolean" + }, + { + "type": "java.lang.ClassValue" + }, + { + "type": "java.lang.Object" + }, + { + "type": "java.lang.String", + "fields": [ + { + "name": "Companion" + } + ] + }, + { + "type": "java.net.StandardSocketOptions" + }, + { + "type": "java.security.AlgorithmParametersSpi" + }, + { + "type": "java.security.KeyStoreSpi" + }, + { + "type": "java.security.interfaces.RSAPrivateKey" + }, + { + "type": "java.security.interfaces.RSAPublicKey" + }, + { + "type": "java.util.List" + }, + { + "type": "java.util.Map" + }, + { + "type": "kotlin.Any" + }, + { + "type": "kotlin.Boolean" + }, + { + "type": "kotlin.Long" + }, + { + "type": "kotlin.Metadata", + "methods": [ + { + "name": "bv", + "parameterTypes": [] + }, + { + "name": "d1", + "parameterTypes": [] + }, + { + "name": "d2", + "parameterTypes": [] + }, + { + "name": "k", + "parameterTypes": [] + }, + { + "name": "mv", + "parameterTypes": [] + }, + { + "name": "pn", + "parameterTypes": [] + }, + { + "name": "xi", + "parameterTypes": [] + }, + { + "name": "xs", + "parameterTypes": [] + } + ] + }, + { + "type": "kotlin.SafePublicationLazyImpl", + "fields": [ + { + "name": "_value" + } + ] + }, + { + "type": "kotlin.String" + }, + { + "type": "kotlin.Unit" + }, + { + "type": "kotlin.collections.List" + }, + { + "type": "kotlin.collections.Map" + }, + { + "type": "kotlin.collections.MutableMap" + }, + { + "type": "kotlin.coroutines.jvm.internal.BaseContinuationImpl" + }, + { + "type": "kotlin.jvm.internal.DefaultConstructorMarker" + }, + { + "type": "kotlin.reflect.jvm.internal.ReflectionFactoryImpl", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition" + }, + { + "type": "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition" + }, + { + "type": "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + }, + { + "type": "kotlinx.coroutines.CancellableContinuationImpl", + "fields": [ + { + "name": "_decisionAndIndex$volatile" + }, + { + "name": "_parentHandle$volatile" + }, + { + "name": "_state$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.CancelledContinuation", + "fields": [ + { + "name": "_resumed$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.CompletedExceptionally", + "fields": [ + { + "name": "_handled$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.DispatchedCoroutine", + "fields": [ + { + "name": "_decision$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.EventLoopImplBase", + "fields": [ + { + "name": "_delayed$volatile" + }, + { + "name": "_isCompleted$volatile" + }, + { + "name": "_queue$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.InvokeOnCancelling", + "fields": [ + { + "name": "_invoked$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.Job" + }, + { + "type": "kotlinx.coroutines.JobSupport", + "fields": [ + { + "name": "_parentHandle$volatile" + }, + { + "name": "_state$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.JobSupport$Finishing", + "fields": [ + { + "name": "_exceptionsHolder$volatile" + }, + { + "name": "_isCompleting$volatile" + }, + { + "name": "_rootCause$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.channels.BufferedChannel", + "fields": [ + { + "name": "_closeCause$volatile" + }, + { + "name": "bufferEnd$volatile" + }, + { + "name": "bufferEndSegment$volatile" + }, + { + "name": "closeHandler$volatile" + }, + { + "name": "completedExpandBuffersAndPauseFlag$volatile" + }, + { + "name": "receiveSegment$volatile" + }, + { + "name": "receivers$volatile" + }, + { + "name": "sendSegment$volatile" + }, + { + "name": "sendersAndCloseStatus$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.flow.StateFlowImpl", + "fields": [ + { + "name": "_state$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.ConcurrentLinkedListNode", + "fields": [ + { + "name": "_next$volatile" + }, + { + "name": "_prev$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.DispatchedContinuation", + "fields": [ + { + "name": "_reusableCancellableContinuation$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.LimitedDispatcher", + "fields": [ + { + "name": "runningWorkers$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.LockFreeLinkedListNode", + "fields": [ + { + "name": "_next$volatile" + }, + { + "name": "_prev$volatile" + }, + { + "name": "_removedRef$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.LockFreeTaskQueue", + "fields": [ + { + "name": "_cur$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.LockFreeTaskQueueCore", + "fields": [ + { + "name": "_next$volatile" + }, + { + "name": "_state$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.Segment", + "fields": [ + { + "name": "cleanedAndPointers$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.internal.StackTraceRecoveryKt" + }, + { + "type": "kotlinx.coroutines.internal.ThreadSafeHeap", + "fields": [ + { + "name": "_size$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.scheduling.CoroutineScheduler", + "fields": [ + { + "name": "_isTerminated$volatile" + }, + { + "name": "controlState$volatile" + }, + { + "name": "parkedWorkersStack$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.scheduling.CoroutineScheduler$Worker", + "fields": [ + { + "name": "workerCtl$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.scheduling.WorkQueue", + "fields": [ + { + "name": "blockingTasksInBuffer$volatile" + }, + { + "name": "consumerIndex$volatile" + }, + { + "name": "lastScheduledTask$volatile" + }, + { + "name": "producerIndex$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.sync.MutexImpl", + "fields": [ + { + "name": "owner$volatile" + } + ] + }, + { + "type": "kotlinx.coroutines.sync.SemaphoreAndMutexImpl", + "fields": [ + { + "name": "_availablePermits$volatile" + }, + { + "name": "deqIdx$volatile" + }, + { + "name": "enqIdx$volatile" + }, + { + "name": "head$volatile" + }, + { + "name": "tail$volatile" + } + ] + }, + { + "type": "sun.security.pkcs12.PKCS12KeyStore", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.DSA$SHA224withDSA", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.DSA$SHA256withDSA", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.JavaKeyStore$DualFormatJKS", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.JavaKeyStore$JKS", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.NativePRNG", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.security.SecureRandomParameters" + ] + } + ] + }, + { + "type": "sun.security.provider.SHA", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.SHA2$SHA224", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.SHA2$SHA256", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.SHA5$SHA384", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.SHA5$SHA512", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.X509Factory", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.provider.certpath.PKIXCertPathValidator", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.rsa.PSSParameters", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.rsa.RSAKeyFactory$Legacy", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.rsa.RSAPSSSignature", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.rsa.RSASignature$SHA224withRSA", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.rsa.RSASignature$SHA256withRSA", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.ssl.KeyManagerFactoryImpl$SunX509", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.ssl.SSLContextImpl$DefaultSSLContext", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory", + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] + }, + { + "type": "sun.security.x509.AuthorityInfoAccessExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.AuthorityKeyIdentifierExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.BasicConstraintsExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.CRLDistributionPointsExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.CertificatePoliciesExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.ExtendedKeyUsageExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.IssuerAlternativeNameExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.KeyUsageExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.NetscapeCertTypeExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.PrivateKeyUsageExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.SubjectAlternativeNameExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + }, + { + "type": "sun.security.x509.SubjectKeyIdentifierExtension", + "methods": [ + { + "name": "", + "parameterTypes": [ + "java.lang.Boolean", + "java.lang.Object" + ] + } + ] + } + ], + "resources": [ + { + "glob": "META-INF/services/ch.qos.logback.classic.spi.Configurator" + }, + { + "glob": "META-INF/services/io.ktor.client.HttpClientEngineContainer" + }, + { + "glob": "META-INF/services/io.ktor.serialization.kotlinx.KotlinxSerializationExtensionProvider" + }, + { + "glob": "META-INF/services/java.lang.System$LoggerFinder" + }, + { + "glob": "META-INF/services/java.net.spi.InetAddressResolverProvider" + }, + { + "glob": "META-INF/services/java.net.spi.URLStreamHandlerProvider" + }, + { + "glob": "META-INF/services/java.nio.channels.spi.SelectorProvider" + }, + { + "glob": "META-INF/services/java.time.zone.ZoneRulesProvider" + }, + { + "glob": "META-INF/services/kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition" + }, + { + "glob": "META-INF/services/kotlin.reflect.jvm.internal.impl.util.ModuleVisibilityHelper" + }, + { + "glob": "META-INF/services/org.slf4j.spi.SLF4JServiceProvider" + }, + { + "glob": "logback-test.scmo" + }, + { + "glob": "logback-test.xml" + }, + { + "glob": "logback.scmo" + }, + { + "glob": "logback.xml" + }, + { + "module": "java.base", + "glob": "jdk/internal/icu/impl/data/icudt76b/nfkc.nrm" + }, + { + "module": "java.base", + "glob": "jdk/internal/icu/impl/data/icudt76b/uprops.icu" + }, + { + "module": "java.base", + "glob": "sun/net/idn/uidna.spp" + } + ], + "bundles": [], + "jni": [ + { + "type": "McpServerKt", + "methods": [ + { + "name": "main", + "parameterTypes": [ + "java.lang.String[]" + ] + } + ] + }, + { + "type": "java.lang.Boolean", + "methods": [ + { + "name": "getBoolean", + "parameterTypes": [ + "java.lang.String" + ] + } + ] + }, + { + "type": "sun.management.VMManagementImpl", + "fields": [ + { + "name": "compTimeMonitoringSupport" + }, + { + "name": "currentThreadCpuTimeSupport" + }, + { + "name": "objectMonitorUsageSupport" + }, + { + "name": "otherThreadCpuTimeSupport" + }, + { + "name": "remoteDiagnosticCommandsSupport" + }, + { + "name": "synchronizerUsageSupport" + }, + { + "name": "threadAllocatedMemorySupport" + }, + { + "name": "threadContentionMonitoringSupport" + } + ] + } + ] +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 8e5292f..895c2d7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,4 +23,5 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") rootProject.name = "ClimateTraceKMP" include(":composeApp") include(":mcp-server") +include(":backend") include(":agents")