Agent AI And MCP (Model Context Protocol)

 

Building My First AI Agent Using MCP and Gemini – Understanding the Complete Flow

When I first started learning AI Agents and the Model Context Protocol (MCP), I found plenty of tutorials that showed how to write the code, but very few explained why each piece exists and how everything works together.

This article explains a simple AI Agent built using:

  • Node.js

  • Google Gemini

  • Model Context Protocol (MCP)

By the end, you'll understand:

  • What an AI Agent actually is

  • How MCP fits into the architecture

  • Why the LLM doesn't need to see tool implementations

  • How tool selection really works


What We Are Building

Our project contains only two files.

app.js
server.js

Although the project is small, it demonstrates the same basic architecture used by many production AI agents.

The flow looks like this:

                User
                  │
                  ▼
               app.js
                  │
      ┌───────────┴────────────┐
      ▼                        ▼
   Gemini LLM             MCP Client
                               │
                           STDIO Transport
                               │
                               ▼
                          MCP Server
                               │
                               ▼
                      getCurrentTime Tool

Notice something important:

Gemini never directly calls the tool.

The application (app.js) coordinates everything.

Our AI Agent project depends on four npm packages. Install them using the following command:

npm install @google/genai @modelcontextprotocol/sdk dotenv zod

This command installs all the required packages and automatically updates the package.json file.


Understanding app.js

The responsibility of app.js is not to calculate the current time.

Its responsibility is to act as the AI Agent.

It performs six jobs:

  1. Connect to Gemini.

  2. Connect to the MCP server.

  3. Discover available tools.

  4. Ask Gemini which tool should be used.

  5. Execute the selected tool.

  6. Ask Gemini to generate the final response.

Let's understand each step.


Step 1 – Connect to Gemini

const ai = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY
});

This creates a client capable of communicating with Gemini.

At this point no AI request has been made.


Step 2 – Start the MCP Server

const transport = new StdioClientTransport({
    command: "node",
    args: ["server.js"]
});

This starts:

node server.js

behind the scenes.

Now the MCP server is running.


Step 3 – Connect the MCP Client

await client.connect(transport);

The client and server are now connected through STDIO.

Think of it as opening a communication channel.


Step 4 – Discover Available Tools

const { tools } = await client.listTools();

This is one of the most important lines in the application.

The agent asks the MCP server:

"Tell me which tools you provide."

The server responds with something similar to:

[
  {
    "name": "getCurrentTime",
    "title": "Current Time",
    "description": "Returns the current system time.",
    "inputSchema": {}
  }
]

Notice that Gemini has not been involved yet.

This communication happens only between the MCP client and MCP server.


Step 5 – Ask Gemini Which Tool to Use

Suppose the user asks:

What is the current time?

Our application creates this prompt:

You are an AI Agent.

User Question:
What is the current time?

Available Tools:
getCurrentTime

Reply ONLY with the tool name.

Gemini responds with:

getCurrentTime

At this point Gemini has only selected the tool.

It has not executed anything.


Step 6 – Execute the Tool

The application now calls:

await client.callTool({
    name: selectedTool,
    arguments: {}
});

The MCP server receives the request and executes the tool.

For our example, the tool returns:

10:45:31 PM

Step 7 – Generate the Final Response

Now the application asks Gemini one more time.

User Question:
What is the current time?

Tool Result:
10:45:31 PM

Write a nice response.

Gemini finally replies:

The current time is 10:45:31 PM.

The user never sees the intermediate steps.


Understanding server.js

The server has only one responsibility:

Provide tools.

It does not communicate with the user.

It does not ask Gemini anything.

It simply exposes capabilities.

Our server registers one tool:

server.registerTool(
    "getCurrentTime",
    {
        title: "Current Time",
        description: "Returns the current system time.",
        inputSchema: {}
    },
    async () => {

        const now = new Date().toLocaleTimeString();

        return {
            content: [
                {
                    type: "text",
                    text: now
                }
            ]
        };
    }
);

This contains two parts.

Metadata

{
    title: "Current Time",
    description: "Returns the current system time.",
    inputSchema: {}
}

This describes what the tool does.

Implementation

async () => {
    const now = new Date().toLocaleTimeString();
    ...
}

This contains the actual JavaScript code.


Does Gemini See the Implementation?

This was the biggest question I had while learning.

The answer is:

No.

Gemini never sees:

const now = new Date().toLocaleTimeString();

Instead, it only receives information similar to:

Tool Name:
getCurrentTime

Description:
Returns the current system time.

This is enough for Gemini to understand when the tool should be used.

The implementation always remains on the server.


Why Doesn't the LLM Need the Code?

Imagine you are given a C# method:

GetCurrentTime()

Even without reading the implementation, you can probably guess what it does.

Programmers intentionally choose descriptive names.

Large Language Models have been trained on millions of code examples and API definitions.

They learn these naming patterns.

When necessary, descriptions provide even more context.

The LLM reasons over the tool's contract, not its implementation.


Is This Really an AI Agent?

Yes.

The application performs the basic agent loop:

User
    │
    ▼
Understand Request
    │
    ▼
LLM Chooses Tool
    │
    ▼
Execute Tool
    │
    ▼
Observe Result
    │
    ▼
LLM Generates Final Answer

This is the foundation of an AI Agent.

More advanced agents add memory, planning, multiple tools, retrieval, and autonomous reasoning, but the core loop remains the same.


Where Does MCP Fit?

One misconception is that MCP is the AI Agent.

It is not.

MCP is simply a communication protocol.

Just as HTTP allows browsers to communicate with web servers, MCP allows AI applications to communicate with tools.

The agent is the orchestration logic.

MCP is one way that the agent talks to external capabilities.


Source Code

The complete source code for this project is available on GitHub.

You can clone the repository, explore the implementation, and run the project locally while following this article.    or   https://github.com/PersonSimple/ai-mcp-tools.git

GitHub Repository: ai-mcp-tools

The repository includes:

  • app.js – Implements the AI Agent by interacting with the Gemini LLM and the MCP Server.

  • server.js – Implements the MCP Server and exposes the getCurrentTime tool.

  • package.json – Contains the project configuration and required npm dependencies.

  • .env.example – Template for configuring your Gemini API key.

  • Complete project structure required to run the application.

Feel free to clone the repository, experiment with the code, extend it with additional MCP tools, and use it as a starting point for building your own AI Agents.



Final Thoughts

Building this small project taught me that AI Agents are not magic.

They are applications that coordinate:

  • an LLM for reasoning,

  • tools for performing actions,

  • and protocols like MCP for communication.

Once I understood that separation, the overall architecture became much easier to understand.

This project may be simple, but it demonstrates the same ideas used by much larger AI systems.

If you're beginning your AI journey, my advice is simple:

Don't just copy the code.

Ask why every line exists.

That's where the real learning happens.

Comments

Popular posts from this blog

Aggregate function with spring data

Thread , Runnable and ExecutorService

Java Persistence API with Spring Data