Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications with Java 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 Java that can be run locally without any unneeded extra code or extensions.
What Is Java?
Java is a high-level, object-oriented programming language and computing platform first released by Sun Microsystems in 1995. It is designed with a “Write Once, Run Anywhere” (WORA) philosophy, allowing compiled code to run on any device with a compatible Java Virtual Machine (JVM) without needing to be rewritten for specific hardware.
For enterprise development, the Java ecosystem offers several robust frameworks and tools, with the Spring ecosystem (especially Spring Boot) and Hibernate being the most widely used and foundational choices.
Spring Boot Java Framework
The Spring Boot framework provides a complete ecosystem for running Java code:
Spring Boot
In practice — the main source site for Open Source production ready Java images is Temurin:
Adoptium
Java Version Management
One of the downsides of the wide deployment of Java has been managing the language versions across platforms and maintaining a supported version.
There are several Java 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:~$
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.
Java MCP Documentation
The Java Spring Boot framework provides first class libraries for implementing MCP:
Connect Your AI to Everything: Spring AI's MCP Boot Starters
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 Java 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 Java MCP server both run in the same local environment.
Next- the basic MCP server is extended with Gemini CLI to add several new tools in standard Java code.
Setup the Basic Environment
At this point you should have a working Java compiler 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 Java Configuration Files — pom.xml
The key file for the Java build and application is the pom.xml file. This file is found in the root directory of the project:
~/gemini-cli-codeassist/mcp-stdio-java
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-java$ ls -l pom.xml
-rw-r--r-- 1 xbill xbill 2819 Dec 18 21:10 pom.xml
For the project build out- Gemini CLI was used to review the file:
> review @pom.xml for a MCP stdio Java demo for spring dependencies
✦ The pom.xml is well-configured for a modern MCP Stdio demo using Spring AI. Here is a detailed review of the dependencies:
Core MCP & AI Dependencies
* `spring-ai-starter-mcp-server`: This is the essential dependency. It provides the core abstractions for MCP (Tools,
Resources, Prompts) and handles the server lifecycle.
* `spring-ai-bom` (1.1.2): Essential for version alignment. MCP is a rapidly evolving specification, and using the BOM ensures
that all Spring AI modules (like the MCP server) are compatible with each other.
* `spring-milestones` Repository: Necessary because 1.1.2 versions of Spring AI are typically found in the milestone/snapshot
repositories rather than Maven Central.
Infrastructure & Communication
* `spring-web`: While this is a Stdio server (standard I/O), spring-ai-starter-mcp-server often depends on spring-web for its
JSON-RPC handling and internal messaging abstractions, even when not running a full HTTP server.
* `jackson-databind`: Critical for the MCP protocol. Every message between the client (like Claude Desktop or Gemini) and your
Java server is a JSON-RPC 2.0 object. Jackson handles the serialization/deserialization of your Tool inputs and outputs.
Environment & Standards
* Java 25: Using the latest Java version allows for clean, modern syntax (Records, Pattern Matching) which makes for a more
readable demo.
* `spring-boot-starter-test`: Includes JUnit 5, Mockito, and AssertJ. This is vital for verifying tool logic without needing
to launch a full MCP client.
* `maven-checkstyle-plugin`: Configured with google_checks.xml. This ensures the "demo" code follows industry-standard style
guidelines, making it more professional and maintainable.
Missing/Optional Considerations
* `spring-boot-configuration-processor`: If your demo grows to include custom @ConfigurationProperties, adding this will
provide IDE autocomplete for your application.properties.
* Logging: spring-boot-starter already includes SLF4J/Logback. Just remember (as per GEMINI.md) to keep logs directed to
System.err so they don't corrupt the System.out JSON stream.
Conclusion: The configuration is "lean and mean"—perfect for a demo as it avoids "dependency bloat" while providing everything
needed for a robust, type-safe MCP server.
Application Properties
The Java build and application execution is also directed by the application resource files:
cd ~/gemini-cli-codeassist/mcp-stdio-java/src/main/resources
ls -ltar
-rw-r--r-- 1 xbill xbill 217 Dec 18 17:54 application.properties
In this demo — here are the current values:
spring.application.name=xbill.mcp.stdio
spring.ai.mcp.server.stdio=true
spring.main.web-application-type=none
spring.main.banner-mode=off
spring.ai.mcp.server.name=xbill-stdio-server
spring.ai.mcp.server.version=1.0.0
Gemini CLI was used to review the file:
✦ The application.properties file is well-configured for a Spring AI MCP stdio server. Here is a review based on the project's
dependencies and best practices:
1. Core MCP Configuration
* spring.ai.mcp.server.stdio=true: Correct and Critical. This enables the stdio transport, allowing the server to communicate
over stdin/stdout, which is the standard for local MCP integrations (e.g., with Claude Desktop).
* spring.ai.mcp.server.name & spring.ai.mcp.server.version: Correct. These are essential for the MCP initialization handshake,
identifying your server to the client.
2. Stdout/Protocol Integrity
* spring.main.banner-mode=off: Excellent. This prevents the Spring Boot ASCII banner from printing to stdout, which would
corrupt the JSON-RPC protocol stream.
* spring.main.web-application-type=none: Excellent. Since this is a stdio server, disabling the embedded web server
(Tomcat/Netty) reduces startup time, memory footprint, and prevents port conflicts.
3. Logging Integration
* While not in application.properties, your logback-spring.xml correctly routes all logs to System.err. This is vital because
System.out is reserved for the MCP protocol.
4. Dependency Alignment
* The properties align perfectly with the spring-ai-starter-mcp-server (version 1.1.2) found in your pom.xml.
* The spring.application.name is consistent with standard Spring Boot practices.
So How Does this all Fit Together?
Java 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 analyse the project and break down how the MCP stdio server was implemented:
✦ The Spring application knows to use the stdio MCP transport through a combination of dependency management and configuration
properties.
Here is the breakdown based on the project files:
1. Dependencies (`pom.xml`):
The project includes the spring-ai-starter-mcp-server dependency. This starter provides the auto-configuration logic for
the Model Context Protocol (MCP) server.
1 <dependency>
2 <groupId>org.springframework.ai</groupId>
3 <artifactId>spring-ai-starter-mcp-server</artifactId>
4 </dependency>
2. Configuration (`application.properties`):
The src/main/resources/application.properties file explicitly enables the stdio transport and configures the application
type:
1 spring.ai.mcp.server.stdio=true
2 spring.main.web-application-type=none
* spring.ai.mcp.server.stdio=true: Tells the MCP server to listen on Standard Input/Output.
* spring.main.web-application-type=none: Ensures Spring Boot doesn't start a web server (like Tomcat), which is crucial
for a CLI/stdio-based tool.
3. Tool Registration (`Application.java`):
The ToolCallbackProvider bean you see in Application.java is detected by the auto-configured MCP server, which then exposes
the registered Tools methods (reverseString, greet) as MCP tools.
Running the Java Code
First- switch the directory with the Java MCP sample code:
cd ~/gemini-cli-codeassist/mcp-stdio-java
Run the release version on the local system:
cd ~/gemini-cli-codeassist/mcp-stdio-java
make release
You can validate the final result by checking the generated JAR file:
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-java$ ls -ltar target/*jar
-rw-r--r-- 1 xbill xbill 26015819 Dec 19 14:04 target/mcp-stdio-java-0.0.1-SNAPSHOT.jar
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-java$
Gemini CLI settings.json
The default Gemini CLI settings.json has an entry for the Java source:
{
"mcpServers": {
"hello-stdio-java": {
"command": "java",
"args": ["-jar",
"$HOME/gemini-cli-codeassist/mcp-stdio-java/target/mcp-stdio-java-0.0.1-SNAPSHOT.jar"
],
"transport": "stdio"
}
}
}
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
> /mcp list
Configured MCP servers:
🟢 hello-stdio-java - Ready (2 tools)
Tools:
- greet
- reverseString
> /mcp schema
Configured MCP servers:
🟢 hello-stdio-java - Ready (2 tools)
Tools:
- greet
Greets the user by name
Parameters:
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the user"
}
},
"required": [
"name"
],
"additionalProperties": false
}
- reverseString
Reverses the input string
Parameters:
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The string to reverse"
}
},
"required": [
"input"
],
"additionalProperties": false
}
The sample Java Tools can be run directly from Gemini CLI:
> greet Duke
✦ I will greet Duke for you.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? greet (hello-stdio-java MCP Server) {"name":"Duke"} ← │
│ │
│ MCP Server: hello-stdio-java │
│ Tool: greet │
│ │
│ Allow execution of MCP tool "greet" from server "hello-stdio-java"? │
│ │
│ 1. Yes, allow once │
│ 2. Yes, always allow tool "greet" from server "hello-stdio-java" │
│ ● 3. Yes, always allow all tools from server "hello-stdio-java" │
│ 4. No, suggest changes (esc) │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greet (hello-stdio-java MCP Server) {"name":"Duke"} │
│ │
│ "Hello, Duke!" │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Hello, Duke
> reverseString Duke
✦ I will reverse the string "Duke" for you.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ reverseString (hello-stdio-java MCP Server) {"input":"Duke"} │
│ │
│ "ekuD" │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ ekuD
Extending the Java MCP Server with Gemini CLI
Now that the basic MCP functionality has been tested and verified with Gemini CLI- the Java server code can be extended with new MCP tools:
> extend the Java MCP stdio project with new tools. One gets the current system time. One gets the current system information.
Once gets the java version information.
✦ The requested tools have been successfully added to mcp-stdio-java.
Summary of changes:
1. Modified `src/main/java/com/example/xbill/mcp/stdio/Tools.java`: Added three new methods annotated with @Tool:
* getCurrentTime(): Returns the current system time in ISO-8601 format.
* getSystemInfo(): Returns the OS name, version, and architecture.
* getJavaVersion(): Returns the Java version, vendor, and home directory.
2. Modified `src/test/java/com/example/xbill/mcp/stdio/ToolsTest.java`: Added unit tests to verify the new tools return valid,
non-empty data.
Verified with make test (all tests passed) and make lint (no style violations).
Build the new release- then restart Gemini CLI and check for the new MCP tools:
make release
gemini
> /mcp list
Configured MCP servers:
🟢 hello-stdio-java - Ready (5 tools)
Tools:
- getCurrentTime
- getJavaVersion
- getSystemInfo
- greet
- reverseString
Now the new MCP tools can be used inside the current context:
> getCurrentTime
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ getCurrentTime (hello-stdio-java MCP Server) {} │
│ │
│ "2025-12-19T14:33:52.578744621" │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I've received your setup and confirmed the current time is 2025-12-19T14:33:52. I'm ready for your first command.
> Hoe many days until the Winter Solstace?
✦ I will check the exact date of the 2025 Winter Solstice to give you an accurate count.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ GoogleSearch Searching the web for: "Winter Solstice 2025 date" │
│ │
│ Search results for "Winter Solstice 2025 date" returned. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The 2025 Winter Solstice is on Sunday, December 21st. Since today is Friday, December 19th, there are 2 days remaining until
the solstice.
The Java Version MCP tool is also live:
> getJavaVersion
✦ I will retrieve the Java version information for you.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ getJavaVersion (hello-stdio-java MCP Server) {} │
│ │
│ "Java Version: 25.0.1, Vendor: Eclipse Adoptium, Home: /home/xbill/.sdkman/candidates/java/25.0.1-tem" │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ You are using Java 25.0.1 (Eclipse Adoptium) located at /home/xbill/.sdkman/candidates/java/25.0.1-tem.
> am I on the latest Java version?
✦ I will search for the latest available Java version to compare it with your current version (25.0.1).
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ GoogleSearch Searching the web for: "latest java version released" │
│ │
│ Search results for "latest java version released" returned. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Yes, you are on the latest major version. Java 25 is the current stable release (LTS), and you are running Java 25.0.1.
The new System information MCP call can also be used:
> getSystemInfo
✦ I will retrieve the system information for you.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ getSystemInfo (hello-stdio-java MCP Server) {} │
│ │
│ "OS Name: Linux, OS Version: 6.6.99-09000-gd3ae1caecf39, Architecture: amd64" │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ You are running Linux (version 6.6.99-09000-gd3ae1caecf39) on an amd64 architecture.
> can I run ARM binaries?
✦ I will check if your system is configured with emulation support (like QEMU) to run ARM binaries.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ Shell which qemu-arm-static || which qemu-aarch64-static || which qemu-arm || which qemu-aarch64 [current working directo… │
│ │
│ Command exited with code: 1 │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will check the kernel configuration for binfmt_misc to see if there is any registered support for ARM architectures.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ Shell ls /proc/sys/fs/binfmt_misc/ [current working directory /home/xbill/gemini-cli-codeassist/mcp-stdio-java] (Listing … │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Based on your system info (amd64) and the absence of QEMU or binfmt_misc configurations, you cannot run ARM binaries natively.
To run them, you would need to install emulation software such as:
1. QEMU User Emulation: Allows running individual ARM binaries.
2. Docker/Podman: Can run ARM containers using QEMU under the hood.
Since which qemu-arm and /proc/sys/fs/binfmt_misc/ returned no results, your system is currently restricted to x86_64 (amd64)
code.
Summary
The strategy for using Java for MCP development with Gemini CLI was validated with a incremental step by step approach.
A minimal stdio transport MCP Server was started from Java 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 Java 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 Java and Gemini CLI was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/local-mcp-development-with-java-and-gemini-cli-69dda57e1b81?source=rss—-e52cf94d98af—4
