Step-by-Step: Let your LLM access Google Drive in Java Using MCP and LangChain4j

Lize Raes
8 min readJan 15, 2025

--

If you’re anything like me, your brain has ultimately degraded over a decade of having electronic devices around that allow you to take notes at any time. You cannot remember anything longer than 1 minute and are now using Google Docs as your mental hard drive.

But ‘remembering’ anything from Google Docs is a pain: taking out your phone, opening the app, finding a file, and then reading it, just to remember to take an in-laws taser on that next family trip.

As true lazy engineers, we’ll solve this problem by writing a little program that lets an LLM access our Google Drive so it can search and summarise our notes, travel plans, and half-written blog posts.

The result will look like this:

Note that I didn’t need to specify the filename, and the file in question contains much more than this list. Great job LLM! (one can tell I’m a back end developer 🙈)

Let’s get this set up in under 20 minutes! (side note: at the moment of writing, the used Google Drive MCP server only allows reading operations, no editing… yet! When editing is added, you can add it in under a minute, just pull the latest version to have the newest functions added, that’s the beauty of MCPs 🙂)

How does it work?

LangChain4j is a Java library that makes connecting to LLMs really easy so you don’t need to construct and parse those API messages yourself. It supports all the main players (OpenAI, Gemini, Anthropic, … ) and also local models, see list of supported models.

Model Context Protocol (MCP) is an open protocol to make tools (and resources) available in LLM-readable format. Everyone can write MCP servers, in any programming language, and open source them for everyone else to use. Amazing ♥️

At the time of writing, over 100 open source MCP servers can be found on github, for services like Notion, Google Calendar, Minecraft, git, … I suppose many more will follow in the coming months. If you’re tempted to write your own, do have a look at this tutorial to write a weather forecast MCP yourself.

This schema illustrates why MCPs are so cool:

Before, you had to study the API of every separate service, get a tool to invoke it, and parse the answer afterwards. So many tools and syntaxes to struggle with! 🤯
MCP servers translate the different APIs to one LLM-readable format, and take care of the invocations. They are language-agnostic and truly plug-and-play.

LangChain4j has an integration to use MCPs as ‘Tools’, you can now plug in any MCP server in just 3 lines of code. Yuppie 🥳 Let’s go!

Prerequisites

You’ll need:

  • Java 17 or higher If your version is insufficient, download java 22 SDK and import it into your IDE.
  • npm Verify if you have it by running npm -v in your terminal/cmd. To install: brew install npm (mac) or choco install npm (windows -> get chocolatey if you don’t have it, it’s the best thing ever)
  • An API Key for the model provider you choose I’m using OpenAI in this example and have set the OPENAI_API_KEY in the environment variables (and restart the IDE!). See here how to set environment variables, here to get an OpenAI key.
  • Google API credentials This is the longest step in the process 😩 But don’t get discouraged, you can reuse these credentials for all Google Services 👍. You’ll need to:
  • Create a Google Cloud Project
  • Enable the Google Drive API here (‘ENABLE APIS AND SERVICES’)
  • Get OAuth credentials here (‘CREATE CREDENTIALS’). You can keep user type ‘external’, add yourself as test user, and choose Desktop App.
  • Alternatively, do ‘+ADD USERS’. You can select the scope for these credentials. For our app we’ll need reading rights for Google Drive.
  • Once that’s done, download the credentials file next to your OAuth 2.0 Client ID user (a file ending in .keys.json), save it somewhere and store the absolute path to this file (incl. the filename at the end) as environment variable GOOGLE_APPLICATION_CREDENTIALS.
  • Also store an environment variable MCP_GDRIVE_CREDENTIALS with the path where the app should store the authentication file (any folder you like). For me the end result looks like this:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/creds_gdrive/gcp-oauth.keys.json
export MCP_GDRIVE_CREDENTIALS=/path/to/creds_gdrive/.gdrive-server-credentials.json
Congrats on your nerves if you made it this far!

Now let’s get some code! Check out the MCP server repo here: https://github.com/felores/gdrive-mcp-server

And run npm installin the project root folder. This should create a dist folder with index.js inside. Save the absolute path to this index.js file, we’ll need it later.

Then check out the LangChain4j examples repo https://github.com/langchain4j/langchain4j-examples and open mcp-examples/src/main/java/dev/langchain4j/example/mcp/McpToolsExampleOverStdio.java

This is the code we’re going to run. Almost there!

The code

In McpToolsExampleOverStudio.java we connect to OpenAI GPT-4o mini. (UncommentlogRequests and logResponses if you want to see what is really sent to theOpenAI endpoint).

  ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
// .logRequests(true)
// .logResponses(true)
.build();

You can swap OpenAI with any supported model provider, but make sure to add the correct dependency to pom.xml, as described in the model integration documentation.

LangChain4j lets you run a published version of the MCP server, via

McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("/opt/homebrew/bin/npm", "exec",
"@modelcontextprotocol/server-filesystem@0.6.2",
new File("./..").getAbsolutePath()
))
.logEvents(true)
.build();

But there are a few reasons to build and invocate your local clone (the other repo we loaded before):

  • Not all MCPs have a published version
  • It’s all quite new, bugfixes are frequent, so for the latest version, you’ll need the source code anyway
  • The published versions tend to clash with Google credentials (for now)

So exchange the McpTransport line with this:

McpTransport transport = new StdioMcpTransport.Builder()
// run with "auth" only the first time, log in when asked, ignore reported errors in terminal
//.command(List.of("/usr/bin/env", "node", "/path/to/gdrive-mcp-server/dist/index.js", "auth"))
.command(List.of("/usr/bin/env", "node", "/path/to/gdrive-mcp-server/dist/index.js"))
.logEvents(true)
.environment(Map.of(
"MCP_GDRIVE_CREDENTIALS", System.getenv("MCP_GDRIVE_CREDENTIALS"),
"GOOGLE_APPLICATION_CREDENTIALS", System.getenv("GOOGLE_APPLICATION_CREDENTIALS")))
.build();

Then change /path/to/gdrive-mcp-server/dist/index.js to the path you obtained in the previous section, after running npm build.

Last thing: set ​​String response = bot.chat(“question”);to a question that makes sense for your Google Drive documents (don’t be too ambitious just yet…)

Now the first time you’ll need to go through the Google authentication process, by uncommenting the ”auth” line

.command(List.of("/usr/bin/env", "node", "/Users/lize/Documents/Code/gdrive-mcp-server/dist/index.js", "auth"))

and commenting out the next one. When you run the code now, you should be brought to a login page like this

Entschuldige mein Deutsch 😂

Walk through it, and say yes to all the unverified-app-asking-for-all-permissions requests 😈

If you make it till this here, you’re good:

You can ignore the errors in your IDE and stop the process.

Comment the ”auth” line out again, and uncomment the next one. Now you’re ready to ask questions to your Google Drive ^^ Have fun!

You’ll soon find out that it doesn’t work well at all. So we’ll tweak our prompt a bit…

Let’s make this work properly

To make this any useful, you’ll want to set proper instructions and give some context to the LLM. You can do so by setting a system message that is passed to the LLM at the beginning of the conversation. Typically it’s used to steer the behaviour of the model, eg. ‘you are talking to a 3-year-old’. For our app, we can add

  • Some static info about you / the user
  • Some dynamic info for context (current date, current location, …)
  • Some extra info on how to use the MCP tools, if their included description is insufficient (as is the case for our example)
  • Some Q&A examples that help the LLM follow your (weird) reasoning

You can set this info on the AiService, in this case the interface Bot.java in the same folder.
AiServices are a super practical concept in LangChain4j, once you’ve wrapped your head around them, they can even return POJOs! If you’re curious, here are examples so you get the hang of them.

To make my Google Drive searcher work better, I prompted it as follows (Bot.java):

public interface Bot {

@SystemMessage("""
User context: the user is {{name}} and you can talk to her like a 3-year-old.
More context: today is {{current_date}}
How to use your tools:
You have tools to search through the user's Google Drive and read file contents.
If you need to search:
- guess the most probable keyword that would be in the filename
- use one keyword only as search query, and use no quotes
- if a probably relevant file pops up, look inside for the answer
- if no relevant file is found, try a second keyword
Some examples of what to query for:
Q: what is my IntelliJ shortcut for searching through the entire project?
Reasoning: the file is probably called IntelliJ shortcuts or similar
Query 1: IntelliJ
Query 2 (if needed): shortcuts

Q: who did I sent Xmas cards to last year?
Reasoning: the file is probably called Christmas cards address list or similar
Query 1: address
Query 2 (if needed): Christmas
Query 3 (if needed): Xmas
Query 4 (if needed): cards

""")
String chat(@UserMessage String prompt, @V("name") String userName);
}

Note that I pass the userName as a second argument for the chat function, so I’ll need to pass this argument as well when I call bot.chat().

Now it should be working much better!

To go further

A side note: if it is really about searching file content only, you may rather want to vectorise your Google Drive, and use that vector database as input for your RAG system. It will be faster, cheaper and more reliable. Here’s more details about RAG and examples.

I’m waiting for editing and file creating capabilities to make this really awesome. Let me know in the comments if you found an MCP repo that does that AND when you get it’s authentication working with Google credentials, thx ☺️

Further reading:

Stay tuned for more articles in the pipeline that risk to never see the light:

  • Connect to Github, Gmail, Calendar, filesystem via MCP
  • Writing our own MCP for filling our supermarket basket (like in: shout orders from the kitchen)
  • Give this stuff a nice frontend (chat, display retrieved contents and permission-to-proceed buttons)
  • Building the audio input side of SiriOnSteroids

--

--

Lize Raes
Lize Raes

Written by Lize Raes

AI Transition Specialist 🚀 | Practical Idealist 🌍 | Keynote Speaker 🎤 | Engineering Lead ⚙️ | Open Source Advocate 🤝 | Naboo.ai 🧠

No responses yet