By now, you’re certainly all familiar with the Model Context Protocol (MCP)?
It’s the standard for connecting Large Language Models (LLMs) to tools and data.
But if you look at the current ecosystem, you’ll see a lot of Python and TypeScript…
As a Java developer, you might be wondering:
How can I easily and quickly run my own MCP servers?
On this blog, I’ve explained how to develop MCP servers
with Quarkus and Micronaut.
But thanks to a recent community contribution
to LangChain4j,
and the simplicity of JBang,
building a local MCP server in Java is even easier and with zero boilerplate.
In RAG, the quality of your generation (when an LLM crafts its answer based on search results)
is only as good as your retrieval (the actually retrieved search results).
While vector search (semantic) and keyword search (BM25) each have their strengths,
combining them often yields the best results.
That’s what we often call Hybrid Search: combining two search techniques or the results of different searches with slight variations.
A few days ago, LangChain4j 1.11.0 was released,
and with this version, a few notable enhancements to the support of the Gemini model family have landed.
Let’s dive in!
Yesterday, I uncovered the Javelit project in this
article
where I built a small frontend to create and edit images
with Google’s Nano Banana image model.
Javelit
Javelit is an open source project inspired by Streamlit from the Python ecosystem
to enable rapid prototyping and deployment of applications in Java.
I recently gave a talk titled “AI Agents, the New Frontier for LLMs”. The session explored how we can move beyond simple request-response interactions with Large Language Models to build more sophisticated and autonomous systems.
If you’re already familiar with LLMs and Retrieval Augmented Generation (RAG), the next logical step is to understand and build AI agents.
What makes a system “agentic”?
An agent is more than just a clever prompt. Itβs a system that uses an LLM as its core reasoning engine to operate autonomously. The key characteristics that make a system “agentic” include:
A very common question I get when presenting and talking about advanced RAG
(Retrieval Augmented Generation) techniques, is
how to best index and search rich documents like PDF (or web pages),
that contain both text and rich elements, like pictures or diagrams.
Another very frequent question that people ask me is about RAG versus long context windows.
Indeed, models with long context windows usually have a more global understanding of a document,
and each excerpt in its overall context. But of course,
you can’t feed all the documents of your users or customers in one single augmented prompt.
Also, RAG has other advantages like offering a much lower latency, and is generally cheaper.
In the first article of this Advanced RAG series, I talked about an approach I called
sentence window retrieval,
where we calculate vector embeddings per sentence, but the chunk of text returned
(and added in the context of the LLM) actually contains also surrounding sentences
to add more context to that embedded sentence.
This tends to give a better vector similarity than the whole surrounding context.
It is one of the techniques I’m covering in my talk on advanced RAG techniques.
Recently on these pages, I’ve covered ADK (Agent Development Kit) for Java, launched at Google I/O 2025.
I showed how to get started writing your first Java agent,
and I shared a Github template that you can use to kick start your development.
But you also know that I’m a big fan of, and a contributor to the LangChain4j project,
where I’ve worked on the Gemini support, embedding models, GCS document loaders, Imagen generation, etc.
Unlike Quarkus and Spring Boot, Micronaut doesn’t (yet?) provide a module to facilitate the implementation of MCP servers (Model Context Protocol).
But being my favorite framework, I decided to see what it takes to build a quick implementation, by vibe coding it, with the help of Gemini!
In a recent article, I explored how to use the MCP reference implementation for Java to implement an MCP server,
served as a servlet via Jetty, and to call that server from LangChain4j’s great MCP support.
One approach with Micronaut may have been to somehow integrate the servlet I had built via Micronaut’s servlet support, but that didn’t really feel like a genuine and native way to implement a server, so I decided to do it from scratch.