skip to Main Content

Local MCP Development with Kotlin and Gemini CLI

January 7, 202613 minute read

  

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications with Kotlin in a local development environment.

Why not just use Python?

Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI approaches with other coding languages. The goal of this article is to provide a minimal viable basic working MCP stdio server in Kotlin that can be run locally without any unneeded extra code or extensions.

What is Kotlin?

Kotlin is a modern, statically typed, general-purpose programming language developed by JetBrains that runs on the Java Virtual Machine (JVM). It is primarily known as the preferred language for Android app development, as announced by Google in 2019.

Kotlin MCP Documentation

Kotlin has an official MCP SDK implementation:

GitHub – modelcontextprotocol/kotlin-sdk: The official Kotlin SDK for Model Context Protocol servers and clients. Maintained in collaboration with JetBrains

Kotlin Version Management

One of the downsides of the wide deployment of Java and Java based tools has been managing the language versions across platforms and maintaining supported versions.

There are several Version Managers available- some may be more suited to your specific environment than others. A good all-around Java Version Manager is SDKMAN:

Home | SDKMAN! the Software Development Kit Manager

The SDKMAN tool is used to download the Java system version- typically this will be a Temurin build. As of writing — the mainstream Java version is Java 25.

To validate your current version:

xbill@penguin:~$ java --version
openjdk 25.0.1 2025-10-21 LTS
OpenJDK Runtime Environment Temurin-25.0.1+8 (build 25.0.1+8-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.1+8 (build 25.0.1+8-LTS, mixed mode, sharing)
xbill@penguin:~$

Install System Packages

Use SDKMAN or another package manager to install the dependent packages — including Kotlin, Java, Gradle, and Maven:

xbill@penguin:~$ sdk install kotlin

kotlin 2.3.0 is already installed.

xbill@penguin:~$ sdk install gradle

gradle 9.2.1 is already installed.

xbill@penguin:~$ sdk install java

java 25.0.1-tem is already installed.
xbill@penguin:~$

xbill@penguin:~$ sdk install maven

maven 3.9.12 is already installed.

Gemini CLI

If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:

npm install -g @google/gemini-cli

Testing the Gemini CLI Environment

Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:

gemini

Node Version Management

Gemini CLI needs a consistent, up to date version of Node. The nvm command can be used to get a standard Node environment:

GitHub – nvm-sh/nvm: Node Version Manager – POSIX-compliant bash script to manage multiple active node.js versions

Gemini CLI needs a minimum Node version of 20 — but as of writing the mainstream Node version is 25.

Where do I start?

The strategy for starting MCP development is a incremental step by step approach.

First, the basic development environment is setup with the required system variables, and a working Gemini CLI configuration.

Then, a minimal Hello World Style Kotlin MCP Server is built with stdio transport. This server is validated with Gemini CLI in the local environment.

This setup validates the connection from Gemini CLI to the local process via MCP. The MCP client (Gemini CLI) and the Kotlin MCP server both run in the same local environment.

Next- the basic MCP server is extended with Gemini CLI to add several new tools.

Setup the Basic Environment

At this point you should have a working Kotlin environment and a working Gemini CLI installation. The next step is to clone the GitHub samples repository with support scripts:

cd ~
git clone https://github.com/xbill9/gemini-cli-codeassist

Then run init.sh from the cloned directory.

The script will attempt to determine your shell environment and set the correct variables:

cd gemini-cli-codeassist
source init.sh

If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:

cd gemini-cli-codeassist
source set_env.sh

Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.

Hello World with STDIO Transport

One of the key features that the standard MCP libraries provide is abstracting various transport methods.

The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

One of the common problems with stdio MCP servers is that the stdout stream gets corrupted with logs or errors and this interferes with the message handling. All logs and errors need to get directed to the stderr stream.

Key Kotlin Configuration Files

The key files for the Kotlin build are reviewed with Gemini CLI:

~/gemini-cli-codeassist/mcp-stdio-kotlin

gemini

✦ I have reviewed the files and confirmed that the best practices and improvements are correctly implemented:

1. Code Style & Naming: The project adheres to standard Kotlin conventions and uses ktlint for enforcement.
2. Error Handling & Robustness: GreetingTool.kt correctly handles missing or empty param arguments, defaulting to "World"
instead of failing. The required list in the schema is empty, correctly reflecting this optionality.
3. Test Coverage: GreetingToolTest.kt includes tests for valid input, null input, and missing parameters, verifying the
default behavior. test_mcp.py is robust, testing the server via stdio with proper JSON parsing and no race conditions.

The project is in excellent shape regarding Kotlin best practices.

So How Does this all Fit Together?

Kotlin is a bit different than many other languages- a combination of settings and conventions allow the application to be auto configured as a MCP stdio server.

Gemini CLI was used to generate a high level summary of the project:

> what does this project do?

✦ I'll start by reading the project's documentation and source code to understand its purpose and functionality.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile README.md │
│ │
│ │
│ ✓ ReadFile GEMINI.md │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I'll now examine the server's entry point and tool implementation to see how it's all put together.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile src/.../example/mcp/server/Main.kt │
│ │
│ │
│ ✓ ReadFile src/.../mcp/server/GreetingTool.kt │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ This project is a Model Context Protocol (MCP) server implemented in Kotlin.

Its primary purpose is to act as a bridge between an MCP client (like a Gemini-integrated IDE or Claude Desktop) and local
tools or resources.

Key Features:
* MCP Server Implementation: Built using the official io.modelcontextprotocol:kotlin-sdk-jvm, providing a robust foundation
for building MCP integrations in the JVM ecosystem.
* Stdio Transport: Communicates with clients via standard input/output, which is the standard for many MCP client-server
connections.
* Built-in Tool (`greet`): Includes a sample tool that accepts a name as a parameter and returns a greeting message.
* Modern Kotlin Stack: Uses Kotlin 2.3.0, Gradle 9.2.1, and JDK 25.
* Testing Infrastructure: Comes with unit tests (using kotlin.test) and a Python script (test_mcp.py) for integration testing
the stdio communication.

In essence, it serves as a "Hello World" template for developers looking to build and deploy their own MCP servers using
Kotlin.

MCP STDIO Server in Kotlin

Gemini CLI was then used to analyse the project and break down how the MCP stdio server was implemented:

✦ Based on the codebase, here is how the MCP server handles tool registration and execution:

1. Tool Definition (GreetingTool.kt)
Tools are defined as objects containing their metadata (schema) and implementation logic.
* Metadata: The GreetingTool object defines a toolDef property. This uses the Tool class from the SDK to specify the tool's
name ("greet"), description, and inputSchema (parameters).
* Logic: The handle function implements the actual behavior, accepting arguments and returning a CallToolResult.

2. Registration (Main.kt)
The server registers tools during startup in the main function using the server.addTool method.

1 server.addTool(
2 GreetingTool.toolDef, // 1. Pass the metadata
3 ) { request -> // 2. Provide the execution handler
4 GreetingTool.handle(request.arguments)
5 }

3. Execution Flow
When an MCP client sends a tools/call request:
1. Routing: The underlying MCP SDK (io.modelcontextprotocol:kotlin-sdk) receives the request and matches the tool name (e.g.,
"greet") to the registered handler.
2. Invocation: The SDK invokes the lambda provided during registration.
3. Processing: The lambda calls GreetingTool.handle(request.arguments).
4. Response: The result is wrapped in a CallToolResult and sent back to the client via the StdioServerTransport.

Running the Kotlin Code

First- switch the directory with the Kotlin MCP sample code:

cd ~/gemini-cli-codeassist/mcp-stdio-kotlin

Run the release version on the local system:

cd ~/gemini-cli-codeassist/mcp-stdio-kotlin

xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-kotlin$ make install
./gradlew installDist

BUILD SUCCESSFUL in 647ms
5 actionable tasks: 1 executed, 4 up-to-date
Consider enabling configuration cache to speed up this build: https://docs.gradle.org/9.2.1/userguide/configuration_cache_enabling.html
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-kotlin$ make run
./gradlew run

> Task :run
2026-01-04 17:57:08.625 [main] INFO com.example.mcp.server.Main - Starting MCP server...
2026-01-04 17:57:08.718 [main] INFO FeatureRegistry[Tool] - Adding Tool: "greet"
2026-01-04 17:57:08.720 [main] INFO FeatureRegistry[Tool] - Added Tool: "greet"
2026-01-04 17:57:08.720 [main] INFO FeatureRegistry[Tool] - Notifying listeners on feature update

Gemini CLI settings.json

The default Gemini CLI settings.json has an entry for the Kotlin source:

{
"mcpServers": {
"hello-stdio-kotlin": {
"command": "/home/xbill/gemini-cli-codeassist/mcp-stdio-kotlin/build/install/mcp-stdio-kotlin/bin/mcp-stdio-kotlin",
"args": [] }
}
}

Validation with Gemini CLI

Finally- Gemini CLI is restarted and the MCP connection over stdio to the Python Code is validated, The full Gemini CLI Session will start:

gemini

Configured MCP servers:

🟢 hello-stdio-kotlin - Ready (1 tool)
Tools:
- greet


> greet Hello Kodee!

✦ I will call the greet tool with the parameter "Hello Kodee!".

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? greet (hello-stdio-kotlin MCP Server) {"param":"Hello Kodee!"} ← │
│ │
│ MCP Server: hello-stdio-kotlin │
│ Tool: greet │
│ │
│ Allow execution of MCP tool "greet" from server "hello-stdio-kotlin"? │
│ │
│ 1. Allow once │
│ 2. Allow tool for this session │
│ ● 3. Allow all server tools for this session │
│ 4. No, suggest changes (esc) │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greet (hello-stdio-kotlin MCP Server) {"param":"Hello Kodee!"} │
│ │
│ Hello, Hello Kodee!! │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Hello, Hello Kodee!

Extending the Kotlin MCP Server with Gemini CLI

Now that the basic MCP functionality has been tested and verified with Gemini CLI- the server code can be extended with new MCP tools:

> extend the MCP stdio project with new tools.  One gets the current system time.  One gets the current system information.
One gets the kotlin system and version information.

✦ I will read src/main/kotlin/com/example/mcp/server/Main.kt and src/main/kotlin/com/example/mcp/server/GreetingTool.kt to
understand the current implementation.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile src/.../example/mcp/server/Main.kt │
│ │
│ │
│ ✓ ReadFile src/.../mcp/server/GreetingTool.kt │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will create SystemTimeTool.kt, SystemInfoTool.kt, and KotlinInfoTool.kt in the src/main/kotlin/com/example/mcp/server/
directory, and then update Main.kt to register these new tools.

Build the new release- then restart Gemini CLI and check for the new MCP tools:

✦ I have successfully extended the MCP stdio project with the requested tools.

Summary of Changes:

1. New Tools Implemented:
* get_system_time (in SystemTimeTool.kt): Returns the current system time in ISO-8601 format.
* get_system_info (in SystemInfoTool.kt): Returns OS name, version, architecture, and available processors.
* get_kotlin_info (in KotlinInfoTool.kt): Returns Kotlin version, Java version, vendor, and home.

2. Tool Registration:
* Updated src/main/kotlin/com/example/mcp/server/Main.kt to register these new tools with the server.

3. Documentation:
* Updated README.md to list and describe the new tools.

4. Verification:
* Built the project using ./gradlew build.
* Fixed ktlint formatting issues.
* Verified functionality using a temporary Python test script (test_new_tools.py) which confirmed all tools respond
correctly over stdio.

You can rebuild and run the server using:
1 ./gradlew build installDist
2 ./build/install/mcp-stdio-kotlin/bin/mcp-stdio-kotlin

Now the new MCP tools can be used inside the current context:

> /mcp list

Configured MCP servers:

🟢 hello-stdio-kotlin - Ready (4 tools)
Tools:
- get_kotlin_info
- get_system_info
- get_system_time
- greet

The new tools can be used directly in the current Gemini CLI context:

> get_kotlin_info

✦ I will now retrieve the Kotlin version and JVM environment information.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ get_kotlin_info (hello-stdio-kotlin MCP Server) {} │
│ │
│ Kotlin Version: 2.3.0 │
│ Java Version: 25.0.1 │
│ Java Vendor: Eclipse Adoptium │
│ Java Home: /home/xbill/.sdkman/candidates/java/25.0.1-tem │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I have retrieved the Kotlin and JVM information. I am ready for your first command.

> am I running the latest version of Kotlin?

✦ I will search for the latest version of Kotlin to see if it matches your current version (2.3.0).

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ GoogleSearch Searching the web for: "latest kotlin version" │
│ │
│ Search results for "latest kotlin version" returned. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Yes, you are running Kotlin 2.3.0, which is currently the latest stable version.

And system information:

> get_system_info

✦ I will now retrieve the system information.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ get_system_info (hello-stdio-kotlin MCP Server) {} │
│ │
│ OS Name: Linux │
│ OS Version: 6.6.99-09000-gd3ae1caecf39 │
│ OS Architecture: amd64 │
│ Available Processors: 12 │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I have retrieved the system information:
- OS Name: Linux
- OS Version: 6.6.99-09000-gd3ae1caecf39
- Architecture: amd64
- Available Processors: 12

✦ Can you run Cyberpunk 2077?
No, your system cannot run Cyberpunk 2077.

The primary bottleneck is your System Memory (RAM), which is significantly below the minimum requirement.

Analysis of Your System vs. Requirements


┌───────────┬───────────────────────────┬────────────────────────────────┬────────────────────┐
│ Component │ Your System │ Minimum Required │ Status │
├───────────┼───────────────────────────┼────────────────────────────────┼────────────────────┤
│ RAM │ 6.3 GB │ 12 GB │ ❌ Fail (Critical) │
│ CPU │ Intel Core i5-1235U │ Core i7-6700 / Ryzen 5 1600 │ ⚠️ Weak │
│ GPU │ Integrated Intel Iris Xe* │ GTX 1060 (6GB) / RX 580 │ ❌ Fail │
│ Storage │ 136 GB Free │ 70 GB SSD │ ✅ Pass │
│ OS │ Linux (Proton) │ Windows 10 (Proton compatible) │ ✅ Pass │
└───────────┴───────────────────────────┴────────────────────────────────┴────────────────────┘


**Based on your CPU (i5-1235U), you likely have integrated graphics unless you have a specific laptop model with a discrete
GPU, but standard tools couldn't detect one.*

Why it won't work:
1. RAM: The game requires 12GB just to start and load assets properly. With only 6.3GB, the game will likely crash on launch
or be unplayably slow due to constant swapping.
2. GPU: The i5-1235U typically relies on Intel Iris Xe integrated graphics. Cyberpunk 2077 is a graphical powerhouse requiring
a dedicated video card (NVIDIA/AMD) with at least 6GB of VRAM (Video RAM). Integrated graphics share your main system RAM
(which is already too low), leading to single-digit frame rates (slide-show performance).

Recommendation:
This machine is better suited for less demanding titles (e.g., Hades, Stardew Valley, Hollow Knight) or older AAA games
(pre-2015), rather than modern heavyweights like Cyberpunk 2077.

Summary

The strategy for using Kotlin for MCP development with Gemini CLI was validated with a incremental step by step approach.

A minimal stdio transport MCP Server was started from Kotlin source code and validated with Gemini CLI running as a MCP client in the same local environment.

Gemini CLI was then used to extend the sample Kotlin code with several MCP tools and use these tools inside the context for the underlying LLM.

This approach can be extended to more complex deployments using other MCP transports and Cloud based options.


Local MCP Development with Kotlin and Gemini CLI was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.

 

Web Developer, Web Design, Web Builder, Project Manager, Business Analyst, .Net Developer

No Comments

This Post Has 0 Comments

Leave a Reply

Back To Top