Skip to content

Commit 5af4856

Browse files
joreillyyschimke
authored andcommitted
Remote MCP Server
1 parent c11285e commit 5af4856

File tree

8 files changed

+157
-55
lines changed

8 files changed

+157
-55
lines changed

agents/src/main/kotlin/adk/adk_agent.kt

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import com.google.adk.agents.LlmAgent
66
import com.google.adk.events.Event
77
import com.google.adk.models.Gemini
88
import com.google.adk.runner.InMemoryRunner
9+
import com.google.adk.tools.AgentTool
10+
import com.google.adk.tools.BaseTool
11+
import com.google.adk.tools.GoogleSearchTool
912
import com.google.adk.tools.LongRunningFunctionTool
1013
import com.google.adk.tools.mcp.McpToolset
1114
import com.google.genai.Client
@@ -26,30 +29,56 @@ class ClimateTraceAgent {
2629
fun initAgent(): BaseAgent {
2730
val apiKeyGoogle = ""
2831

29-
// val mcpTools = McpToolset(
30-
// ServerParameters
31-
// .builder("java")
32-
// .args("-jar", "/Users/joreilly/dev/github/ClimateTraceKMP/mcp-server/build/libs/serverAll.jar", "--stdio")
33-
// .build()
34-
// ).loadTools().join()
32+
val climateTools = McpToolset(
33+
ServerParameters
34+
.builder("java")
35+
.args("-jar", "/Users/joreilly/dev/github/ClimateTraceKMP/mcp-server/build/libs/serverAll.jar", "--stdio")
36+
.build()
37+
).loadTools().join()
38+
39+
// val getCountriesTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getCountries")
40+
// val getEmissionsTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getEmissions")
41+
// val climateTools = listOf(getCountriesTool, getEmissionsTool, GoogleSearchTool())
3542

36-
val getCountriesTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getCountries")
37-
val getEmissionsTool = LongRunningFunctionTool.create(ClimateTraceTool::class.java, "getEmissions")
38-
val mcpTools = listOf(getCountriesTool, getEmissionsTool)
3943

4044
val model = Gemini(
41-
"gemini-1.5-pro",
45+
"gemini-2.0-flash",
4246
Client.builder()
4347
.apiKey(apiKeyGoogle)
4448
.build()
4549
)
4650

47-
return LlmAgent.builder()
48-
.name(NAME)
51+
52+
val searchAgent = LlmAgent.builder()
53+
.name("SearchAgent")
54+
.model(model)
55+
.description("Google Search agent")
56+
.instruction("You're a specialist in Google Search")
57+
.tools(GoogleSearchTool())
58+
.build()
59+
60+
val climateAgent = LlmAgent.builder()
61+
.name("ClimateAgent")
4962
.model(model)
5063
.description("Agent to answer climate emissions related questions.")
5164
.instruction("You are an agent that provides climate emissions related information. Use 3 letter country codes.")
52-
.tools(mcpTools)
65+
.tools(climateTools)
66+
.build()
67+
68+
return LlmAgent.builder()
69+
.name(NAME)
70+
.description("Agent to answer climate emissions related questions.")
71+
//.instruction("You are an agent that provides climate emissions related information. Use 3 letter country codes. Use SearchAgent for population data.")
72+
.instruction("""
73+
You are an agent that provides climate emissions related information.
74+
75+
Use `ClimateAgent` for emission data.
76+
Use `SearchAgent` for population data.
77+
""")
78+
79+
.model(model)
80+
//.subAgents(searchAgent, climateAgent)
81+
.tools(AgentTool.create(searchAgent), AgentTool.create(climateAgent))
5382
.build()
5483
}
5584
}

backend/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

backend/build.gradle.kts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)
2+
3+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
4+
5+
plugins {
6+
kotlin("multiplatform")
7+
alias(libs.plugins.kotlinx.serialization)
8+
alias(libs.plugins.shadowPlugin)
9+
alias(libs.plugins.jib)
10+
}
11+
12+
kotlin {
13+
jvm() {
14+
withJava()
15+
binaries {
16+
executable {
17+
mainClass.set("ServerKt")
18+
}
19+
}
20+
}
21+
22+
sourceSets {
23+
jvmMain.dependencies {
24+
implementation(libs.kotlinx.coroutines)
25+
implementation(libs.kotlinx.serialization)
26+
27+
implementation("io.ktor:ktor-server-core:3.2.1")
28+
implementation("io.ktor:ktor-server-netty:3.2.1")
29+
implementation("io.ktor:ktor-server-cors:3.2.1")
30+
implementation("io.ktor:ktor-serialization-kotlinx-json:3.2.1")
31+
implementation("io.ktor:ktor-server-content-negotiation:3.2.1")
32+
33+
implementation("ch.qos.logback:logback-classic:1.5.8")
34+
35+
//implementation(projects.composeApp)
36+
implementation(libs.mcp.kotlin)
37+
implementation(projects.mcpServer)
38+
}
39+
}
40+
}
41+
42+
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
43+
manifest {
44+
attributes["Main-Class"] = "ServerKt"
45+
}
46+
}
47+
48+
tasks.withType<Tar> { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
49+
tasks.withType<Zip> { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
50+
51+
52+
jib {
53+
from.image = "docker.io/library/eclipse-temurin:21"
54+
55+
to {
56+
image = "gcr.io/climatetrace-mcp/climatetrace-mcp-server"
57+
}
58+
container {
59+
ports = listOf("8080")
60+
mainClass = "ServerKt"
61+
}
62+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import io.ktor.server.application.*
2+
import io.ktor.server.cio.CIO
3+
import io.ktor.server.engine.*
4+
import io.ktor.server.netty.*
5+
import io.ktor.server.response.respond
6+
import io.ktor.server.routing.*
7+
import io.ktor.server.sse.SSE
8+
import io.modelcontextprotocol.kotlin.sdk.server.mcp
9+
10+
11+
12+
fun main() {
13+
val server = configureMcpServer()
14+
15+
val port = System.getenv().getOrDefault("PORT", "8080").toInt()
16+
embeddedServer(CIO, port, host = "0.0.0.0") {
17+
install(SSE)
18+
19+
routing {
20+
mcp {
21+
server
22+
}
23+
24+
get("/hi") {
25+
call.respond("hello!!")
26+
27+
}
28+
}
29+
}.start(wait = true)
30+
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/data/ClimateTraceRepository.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ class ClimateTraceRepository(
1010
private val api: ClimateTraceApi
1111
) {
1212
suspend fun fetchCountries() : List<Country> {
13-
val countries: List<Country>? = store.get()
14-
if (countries.isNullOrEmpty()) return api.fetchCountries().also { store.set(it) }
15-
return countries
13+
// val countries: List<Country>? = store.get()
14+
// if (countries.isNullOrEmpty()) return api.fetchCountries().also { store.set(it) }
15+
// return countries
16+
return api.fetchCountries()
1617
}
1718

1819
suspend fun fetchCountryEmissionsInfo(countryCode: String, year: String) = api.fetchCountryEmissionsInfo(listOf(countryCode), year)

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/remote/ClimateTraceApi.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,21 @@ import io.ktor.client.request.get
66
import kotlinx.serialization.SerialName
77
import kotlinx.serialization.Serializable
88

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

16+
/**
17+
* Represents a single asset.
18+
* @property id The unique identifier of the asset.
19+
* @property name The name of the asset.
20+
* @property assetType The type of the asset.
21+
* @property sector The sector to which the asset belongs.
22+
* @property thumbnail A URL to a thumbnail image for the asset.
23+
*/
1224
@Serializable
1325
data class Asset(
1426
@SerialName("Id")
Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
version = "1.7">
4-
<BuildAction
5-
parallelizeBuildables = "YES"
6-
buildImplicitDependencies = "YES">
3+
version = "1.3">
4+
<BuildAction>
75
<BuildActionEntries>
86
<BuildActionEntry
9-
buildForTesting = "YES"
10-
buildForRunning = "YES"
11-
buildForProfiling = "YES"
12-
buildForArchiving = "YES"
13-
buildForAnalyzing = "YES">
7+
buildForRunning = "YES">
148
<BuildableReference
159
BuildableIdentifier = "primary"
1610
BlueprintIdentifier = "7555FF7A242A565900829871"
@@ -21,25 +15,11 @@
2115
</BuildActionEntry>
2216
</BuildActionEntries>
2317
</BuildAction>
24-
<TestAction
25-
buildConfiguration = "Debug"
26-
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
27-
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
28-
shouldUseLaunchSchemeArgsEnv = "YES"
29-
shouldAutocreateTestPlan = "YES">
30-
</TestAction>
3118
<LaunchAction
32-
buildConfiguration = "Debug"
33-
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
34-
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
35-
launchStyle = "0"
3619
useCustomWorkingDirectory = "NO"
37-
ignoresPersistentStateOnLaunch = "NO"
38-
debugDocumentVersioning = "YES"
39-
debugServiceExtension = "internal"
20+
buildConfiguration = "Debug"
4021
allowLocationSimulation = "YES">
41-
<BuildableProductRunnable
42-
runnableDebuggingMode = "0">
22+
<BuildableProductRunnable>
4323
<BuildableReference
4424
BuildableIdentifier = "primary"
4525
BlueprintIdentifier = "7555FF7A242A565900829871"
@@ -49,18 +29,4 @@
4929
</BuildableReference>
5030
</BuildableProductRunnable>
5131
</LaunchAction>
52-
<ProfileAction
53-
buildConfiguration = "Release"
54-
shouldUseLaunchSchemeArgsEnv = "YES"
55-
savedToolIdentifier = ""
56-
useCustomWorkingDirectory = "NO"
57-
debugDocumentVersioning = "YES">
58-
</ProfileAction>
59-
<AnalyzeAction
60-
buildConfiguration = "Debug">
61-
</AnalyzeAction>
62-
<ArchiveAction
63-
buildConfiguration = "Release"
64-
revealArchiveInOrganizer = "YES">
65-
</ArchiveAction>
6632
</Scheme>

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2323
rootProject.name = "ClimateTraceKMP"
2424
include(":composeApp")
2525
include(":mcp-server")
26+
include(":backend")
2627
include(":agents")

0 commit comments

Comments
 (0)