MCP & A2A - Model Context Protocol & Agent to Agent Protocol | Skillshare Member | Skillshare

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

MCP & A2A - Model Context Protocol & Agent to Agent Protocol

teacher avatar Skillshare Member

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Course Introduction

      1:48

    • 2.

      1.1 MCP Overview - What is Model Context Protocol?

      4:36

    • 3.

      1.2. Get Code on Github

      1:56

    • 4.

      SECTION 2 START - Build Your Own MCP Server - 2.1 Introduction to MCP Server and 1 Minute Preview of

      1:17

    • 5.

      2.2 Install Claude for Desktop

      1:11

    • 6.

      2.3 Install Python, UV and VS Code

      2:52

    • 7.

      2.4 Setup Project Directories and Files

      1:48

    • 8.

      2.5 MCP Server Python Code Walkthrough

      1:35

    • 9.

      2.6 Connect Server to Claude Desktop and Test Your Server

      12:59

    • 10.

      SECTION 3 START - Build Your Own MCP Client (Using Python + Google Gemini API) - 3.1 Quick Recap and

      2:24

    • 11.

      3.2 How to Get Free Gemini API Key

      1:51

    • 12.

      3.3 Setup Project Directories, Files & Install Google-GenAI SDK

      2:14

    • 13.

      3.4 MCP Client Python Code Walkthrough

      10:33

    • 14.

      3.5 Test Your MCP Client with Your MCP Server

      2:26

    • 15.

      SECTION 4 - Containerize your MCP Server Using Docker

      14:41

    • 16.

      SECTION 5 - Simplify client code with LangGraph & LangChain

      11:28

    • 17.

      SECTION 6 START Build MCP Client with Multiple Server Support: 6.1 Introduction

      0:36

    • 18.

      6.2 Let's look at the config.json file

      0:36

    • 19.

      6.3 Demo - MCP Client with Multiple MCP Servers

      4:10

    • 20.

      6.4 MCP Client (with json config) Code Walk Through - Part 1

      2:23

    • 21.

      6.5 Why Choose Gemini 2.0 Flash and not the Pro Models

      0:47

    • 22.

      6.6 MCP Client (with json config) Code Walk Through - Part 2 (continued)

      3:52

    • 23.

      6.7 How to use existing MCP servers from MCP Github (example uses "fetch" server)

      3:57

    • 24.

      SECTION 7 START - Server Sent Events - MCP Server and Clients using SSE - 7.1 Introduction

      0:58

    • 25.

      7.2 Quick Recap, What is STDIO and SSE?

      2:12

    • 26.

      7.3 Setup Directories, Clone GitHub Code (git pull only, if done at course start)

      1:35

    • 27.

      7.4 Setup Virtual Environment and Dependencies

      2:27

    • 28.

      7.5 MCP SSE Server Code Walkthrough

      8:57

    • 29.

      7.6 MCP SSE Client Code Walkthrough

      14:10

    • 30.

      7.6 Dockerfile Code (for MCP Server) Walkthrough

      0:55

    • 31.

      7.7 Test your MCP SSE Server and Client Locally

      2:36

    • 32.

      SECTION 8 START - Deploying MCP Server to Google Cloud Platform - 8.1 Create a new Gmail Account (if

      2:34

    • 33.

      8.2 Create a Google Cloud Project

      2:48

    • 34.

      8.3 Install and Setup Google Cloud Command Line Interface (gcloud CLI)

      5:33

    • 35.

      8.4 Build Docker Image for Google Cloud

      1:02

    • 36.

      8.5 Deploy MCP SSE Server to Google Cloud Run

      0:58

    • 37.

      8.6 Test MCP SSE Server on Google Cloud

      2:04

    • 38.

      SECTION 9 START - STREAMABLE HTTP MCP SERVER - 9.1 Quick MCP Recap and What is Streamable HTTP

      3:52

    • 39.

      9.2 Overview of Streamable HTTP using Sequence Diagram

      2:54

    • 40.

      9.3 Initialisation Phase

      2:12

    • 41.

      9.4 Client Requests Phase of Streamable HTTP

      1:46

    • 42.

      9.5 MCP Client Notifications and Responses

      0:45

    • 43.

      9.6 Client Listening to Messages from the Server in Streamable HTTP

      1:19

    • 44.

      9.7 Session handling in Streamable HTTP

      1:57

    • 45.

      9.8 External Resource for keeping up to date

      1:57

    • 46.

      SECTION 10 START - Streamlit User Interface for MCP Client - 10.1 Streamlit UI MCP Client Overview

      2:35

    • 47.

      10.2 Streamlit UI Demo

      2:39

    • 48.

      10.3 Comparing our UI with Claude Desktop!

      0:26

    • 49.

      10.4 Setup Directories (skip if done earlier)

      0:54

    • 50.

      10.5 Setup Google Gemini API Key (verify again if done earlier)

      1:37

    • 51.

      10.6 Create Virtual Environment and Install Dependencies

      1:39

    • 52.

      10.7 Get Streamlit UI Code

      1:00

    • 53.

      10.8 Streamlit App Imports and State Initialisation

      3:35

    • 54.

      10.9 Code for Utility Functions

      1:15

    • 55.

      10.10 Streamlit App Sidebar Code

      3:21

    • 56.

      10.11 Building the Main Chat UI for the App

      3:04

    • 57.

      10.12 Core Logic For Query Handling

      1:35

    • 58.

      10.13 Trigger Logic for Send and Other Chat Buttons

      1:41

    • 59.

      10.14 Streamlit App MCP Client Code

      7:04

    • 60.

      10.15 theailanguage_config.json and other files

      1:35

    • 61.

      10.16 Running the Streamlit UI

      0:18

    • 62.

      SECTION 11 START - A2A or Agent to Agent Protocol - Lifecycle - 11.1 Introduction

      2:56

    • 63.

      11.2 Why A2A Protocol - A2A vs MCP

      2:09

    • 64.

      11.3 Discovery - A2A Client, A2A Server, Agent Card

      2:43

    • 65.

      11.4 Initiation - Tasks, Messages, Parts

      1:53

    • 66.

      11.5 Processing - Artifacts, Streaming, Push Notifications, Non-streaming

      1:42

    • 67.

      11.6 Interaction - input-required state

      0:22

    • 68.

      11.7 Completion Flow & Summary of A2A

      1:35

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

2

Students

--

Projects

About This Class

Class Overview: In this hands-on coding course, you'll learn about Model Context Protocol (MCP) and Agent-to-Agent (A2A) Protocol-the foundational technologies that enable AI agents to communicate, collaborate, and access external tools. You'll build 5 MCP Clients and 3 MCP Servers from scratch, create a Streamlit-based UI for your client in Python, and deploy your MCP Server to Google Cloud using Server Sent Events (SSE). To top it off, we'll use a free Gemini API key from Google, so you can explore these powerful technologies without any cost for AI models.

You'll also implement Agent-to-Agent (A2A) Protocol to connect multiple agents, and build a Host Orchestrator Agent that integrates both MCP and A2A using Google’s Agent Development Kit (ADK).

What You Will Learn

  • Agent-to-Agent (A2A) Protocol: Connect 3 agents and build a host orchestrator using A2A + MCP.

  • Build 5 MCP Clients & 3 MCP Servers from Scratch – full working code included.

  • Design a UI in Streamlit for your MCP Client in Python.

  • Deploy your MCP Server on Google Cloud using Server Sent Events (SSE).

  • Use Google’s Gemini API (free key) to run AI-powered agents at no cost.

  • Work with Python, Gemini, LangGraph, SSE, Streamlit on macOS.

Why You Should Take This Class

  • MCP allows AI agents to interface with external tools and APIs.

  • A2A enables agent collaboration across technical and organizational boundaries.

  • These protocols form the communication backbone for modern autonomous agent systems.

  • I’ve been building and teaching A2A and MCP-based agent systems that generate code and perform complex tasks - and I’m excited to guide you through building them too.

Who This Class is For

  • Developers looking to build MCP clients, servers, and user interfaces.

  • AI agent developers, LangChain developers, and software engineers.

  • Entrepreneurs and product builders seeking a QuickStart on MCP + A2A.

Materials / Resources

  • This course is recorded on macOS - access to a macOS machine is highly recommended.

  • Windows instructions will be provided where relevant (ETA: end of July, as part of Github Repositories).

  • Linux instructions are currently not available and not under plan to be added later.

  • You’ll get access to a GitHub repo with all project code

  • MCP Server Code - https://github.com/theailanguage/terminal_server

  • MCP Client Code - https://github.com/theailanguage/mcp_client

  • A2A Code - https://github.com/theailanguage/a2a_samples
  • MCP and A2A are evolving protocols - breaking changes may occur. The instructor will then try to update the codes to reflect the changes as soon as possible

  • Basic Python knowledge is required.

  • Familiarity with LLMs (like Gemini or Claude) is required.

Meet Your Teacher

Level: Advanced

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Course Introduction: Hi, everyone. Welcome to this course on MCP and eightway which is Model Context Protocol and agent to Agent protocol. I'm Karthick, an alumnus of IIT Deli and University of Illinois. Currently, I'm building AI agents that can write software at my startup, the AI language, and I'm incredibly excited to share this journey with you. The Model Context protocol allows host agents to connect with and manage external tools and resources from servers called MCP servers. This helps to extend the capabilities of agents by providing them external tools and resources. Agent to agent protocol is a communication standard that allows multiple agents to discover each other and talk to each other directly whether local or remote. This allows them to collaborate, delegate tasks, and work together in a larger system across organizational and technical boundaries. Together, they form a communication backbone for a powerful multi agent system, allowing agents to expand their capabilities by connecting to external tools and agents and collaborating together. So what will you learn in this course? We'll start with MCP and you'll build five MCP clients and three MCP servers from scratch, full working code included. We learn to deploy our MCP server to Google Cloud. We'll build a UI for MCP client in Streamlt in Python, and then we'll move on to agent to agent protocol. We'll connect three agents via a tow and build a host orchestrator agent that can connect via Ata to other agents and via MCP to other MCP servers. Finally, we'll use a free Gemini API key so you don't need to pay for AI models when learning, and we'll do all this on Mac OS, but I'll provide written instructions for Windows users so you can follow along. So if you're ready to start building with MCP and at, let's get started, see you in the first lesson. 2. 1.1 MCP Overview - What is Model Context Protocol?: Hi, everyone. Today we are going to look at the basics of Model Context protocol and understand what this is. This you can see is a news article 0R a blog post from Anthropic from 25th, November 2024 when they introduced the Model Context protocol. But the best way to follow this is by clicking on this link, which will take you to modelctextprotocol dot IO, and you have this website over here with some documentation on getting started and some tutorials, and this will help you. But before we do that, let's just go through the basics. So what is Model Context protocol? It is basically a protocol to connect large language models, which might be hosted on some apps using this particular protocol to external data sources and tools that would be exposed by servers. So essentially, it's a client server model. So this is your client over here, and the MCP client or the model context protocol client connects to MCP servers using this particular protocol. Now, what are the clients over here? The clients are LLM powered apps like Cloud desktop or IDs or tools that basically host an LLM onto them. And the servers are programs that expose tools, resources, or prompts. These are the three primitives that they basically expose and help the LLM to execute these functions or tools, use the resources or basically get some sample prompts. The servers might further connect with local data sources like local data source A, B, and so on, or through web APIs to remote services like remote service C over here, as shown on their documentation website. So let's talk about the MCP server first. So this basically provides three primitives, and you can actually go to the Quickstart over here for server developers. And when you scroll down, you'll actually see these primitives mentioned over here. So these resources provide access to external data and files for the large language model to retrieve information. So your client application connecting to the server can then access this particular information through these resources. There are tools, and these tools are essentially what we are used to seeing with large language models and agents, which we provide these tools, and these are basically functions or APIs for the LLM to invoke. And this helps this helps the large language model perform actions. And then there are prompts. So these are reusable templates with instructions or context to guide the large language model behavior, and your client app can basically use this by connecting to the servers using the MCP protocol. Okay, so heading back to the introduction, there are also two primitives that the client provides, and these are not mentioned over here, but let's just go through them. So these are roots which are interfaces or entry points through which the client connects to the MCP servers. And sampling. Sampling is basically a mechanism that the server can actually request the client to generate text based on specific inputs or context. This is what the client provides as part of the protocol. Now, given these primitives, we can see that this is bidirectional. So with these primitives, MCP supports two way communication between the server and the client. So a server can request the LLM to generate completions, which is the sampling primitive. At the same time, the client hosting the large language model can request a tool execution on the server and then request for the result, or it can ask for some kind of data information or some information from a remote service. So that is basically what model context protocol is. It's a bidirectional protocol for clients to connect to servers. And on the servers, you have the resources, prompts, and tools, and on the clients, you have the roots and the sampling primitives that basically help the large language model and the server to communicate with each other. There are several pre built MCP servers that exist for Github, Google Drive, Post cress, et cetera, still early stage and the success of this depends on wider adoption by a lot of people, but it has been seen, if you follow a lot of Twitter threads, you can actually see a lot of people working with MCP these days and mentioning it as one of the next big things in EI. So for example, you might have a MCP server to connect a large language model to a local SQLI database, a Github bo, and a Slack workspace all in the same protocol. So LLM can query the database. They can fetch the code context, and they can post updates all within a single protocol. So that's all for MCP for now. Thanks a lot for watching. 3. 1.2. Get Code on Github: Now that we know about the basics of MCP, let me first cover a housekeeping item which is about the course repository where I'll be pushing all the code, which can actually clone and use during all the different lectures. To access the code repositories, please go to github.com slash the AI Language, and then you can click on repositories to visit the repositories tab. You'll see several repositories by the AI language over here, and we'll be basically using two repositories, the MCP client repository. And the terminal server repository. The MCP client will basically have the implementation using Python, Lang rap, Gemini, and any other clients that we implement. If I add another repository for any of the other lectures, I'll be mentioning that during the course. The other repository is for the MCP server, and I've called this terminal server because the server that we use in the course is used to run commands on the terminal, and this is an MCP server that can execute terminal commands. To open a repository, just simply click on the name of the repository. And you can see all the files over here along with the read me over here. And if you actually want to clone the code, you can click on code over here and use one of the specific methods that you prefer. For example, you can use SDDPS and copy this link and then go to your terminal and type Git clone with this link to actually clone this. So I request you to please start this repository and watch this by clicking on these two items like I have already done over here, and then you can actually go back to the AI language and then go to the terminal server over here. And also check out this code again in the same way by clicking on code and using one of your preferred methods from over here. Again, please also star and watch this repository so that you have it ready for easy deference on your Github account. 4. SECTION 2 START - Build Your Own MCP Server - 2.1 Introduction to MCP Server and 1 Minute Preview of: Hi everyone. Today we are building an MCP server that can execute commands on terminal on your local MacBook. This means you can ask AI apps like Cloud for Desktop to run commands on your computer and send back the output, just like using a terminal, but through AI. Here's a preview of what we'll actually test at the end, and it's absolutely amazing. Let me tell you that. And what I've done is basically, can you create a directory called Cloud output? Make a file inside it, called terminal Underscore server underscoe test dot DHT. And then it says, I'll help you create a directory and file as requested. So let's ask Cloud. Can you open this using code? The terminal server test dottXDFle. And let's before that, add some text. So can you add the text? I successfully made my first MCP server to this file, and then can you open this using code? The terminal underscoe server dot DF. So let's send this message. So here you have it. So, guys, isn't this amazing? You have made actually an MCP server that can actually run terminal commands, and you used a large language model on an app, which is your MCP client, the Cloud desktop app, and you actually controlled your computer by creating a file, adding some text to it with the Smiley and then opening it in 5. 2.2 Install Claude for Desktop: As a first step, let's install this client and you can do that by searching for Cloud desktop. Let's search for that and let's click on Download over here and you get to this website for downloading it, and click on MacOS because we are on MacOS Windows folks can actually use the Windows Link over here. Let's wait for a minute for this to download. All right. Once it's downloaded, let's just open this and drag Cloud two applications over here. Now launch cloud by typing Cloud over here and press Open. Let's click on open. So now you need to log in. So let's login with Google account. So if you're using Cloud for the first time, you need to enter your full name. All right. So once you've signed in, you'll see a welcome screen like this. Good afternoon, the A language, and we have the Cloud 3.7 Sonnet model over here. This is the desktop app for Cloud for MacOS, and it will give you 40 messages for free per day, so you don't need to actually pay initially to do this tutorial. 6. 2.3 Install Python, UV and VS Code: So the next thing that we want to do is to install Python. So if you already have Python installed, you can check for the version over here. You can type Python three dash version. And for example, we have 3.9 0.6, but we need 3.10 or higher. So to install the latest version of Python, we can open a new browser window and say, install Python. And let's go to the download Python page over here. All right. Let's click on download Python 3.13 0.2. And let's wait for the download to complete. So once this is completed, you can actually open this, and you get an installed Python window like this. There's an introduction. Let's continue. There's a read me over here. So let's continue over here. And there's a license, I'm going to accept it. I'm going to use the standard installation and not going to customize for now, and let's enter our password. And this is not going to install Python for us. All right. So we have Python installed now. Let's move the installer to the bin this is going to actually open this Python 3.13 folder over here and it's going to show you all the things that are installed, including the IDLE. Now, let's go back to the terminal. Let's type which Python three, and this shows you that this is installed to user local Bin Python three, so we can now type Python three version, and we see that our Python three is now 3.13 0.2. This actually satisfies our version requirement for 3.10 and higher. We're good with this now. Now, next, we want to install UV, which is a fast package manager for Python that helps us install and run dependencies. So to install that, we're going to paste this command, and you can find this in the description. Press Enter. So let's wait for some time for this to get installed. All right. So there's a permission denied error, and you might want to then and we can see that the error is due to the ownership of local being with root. The local directory is inside our home directory, so we can actually change the permission over here. So use this command for this, enter your password, and then let's verify if the ownership has been updated. And yes, we can see that the ownership is now updated over here. This permission fail, you might be tempted to run this, with pseudo. But running with sudo might install this as root, which could cause permission issues later. So let's not do that, and let's update this permission like this. And let's not try to install UV again and see if it works. Alright, great. So everything's installed. Let's source our environment file so that we can recognize the command UV. And let's type UV dash version. And we can see that UV is now installed. This is the package manager that we wanted. If you're on a Windows machine, you can actually follow the install instructions on the UV page on Github by Astral, and if you scroll on over here, you have the installation over here. 7. 2.4 Setup Project Directories and Files: Now we are going to create the MCP directory structure. So MCP is our root directory, and inside this there servers, and we might make multiple servers. For the current server that we're making, which is what we're calling a terminal server, we're going to make a new folder over here, and this is that directory structure. We also going to make a workspace directory so that all the work that you Clouds desktop app does for us using our MCP server is done inside this workspace directory. So if it runs a terminal command to do something to create a folder, for example, or directory, it actually does it inside the workspace directory. Let's press center now. Let's change to our terminal server directory. So just to reiterate, MCP will save everything related to MCP, including our server, which will be inside the servers directory. And there'll be a dedicated workspace inside the workspace directory over here. Each server will have its own folder. For now, I've just created one, which is terminal server. So now we are going to initialize a Python project inside terminal server. For that, we just type UV in it, and it's done that. Now, let's create a virtual environment. So for that we type UV, V and V, and let's activate it. Now, this creates a virtual environment which keeps our projects dependencies separate from the system's Python installation. Now we need to install the MCP package which allows our server to communicate with Claude. So for that, we'll do UV, add MCP CLI and presenter. All right, so that's now installed. So now let's write the code to execute terminal commands. So first, create a new file, terminal underscore server dot PY. Now, let's head over to VS code, and let's click on open over here. So we see the MCP folder over here that we just created, and we see the servers over here and we open our terminal server. So let's open this. So I'm going to trust the authors over here. And then let's go to what terminal underscore server dot PY file. 8. 2.5 MCP Server Python Code Walkthrough: First we are going to import the necessary code. We import the required libraries, subprocess lets us run terminal commands and fast MCP helps us set up an MCP server. The workspace directory is always set to MCP workspace. Now we are going to define the tool that's going to help us run the commands on the terminal. So let's break down this function step by step. This is a decorator, as we call it, and this registers the function as an MCP tool. This is what allows Cloud for desktop or any MCP client to call this function as an external tool. This entire thing over here is what defines the function. This basically means that the function expects a string input, which is the shell command that it needs to execute. And this will be provided by the Large language model as an input, and it's going to be a string. And the function will return a string back which will contain the entire command's output or an error message which you can see over here. This is the line that runs the command on the terminal, and this is what resounds the output. We use a simple try except block over here to basically catch any errors that might happen. So if something unexpected happens, example, missing permissions, invalid commands, the error message is caught and returned as a string to your large language model, and then the large language model can basically take a decision on that. All right, so now we're basically going to start the server, and this starts the MCP server allowing Cloud to communicate with it. Let's save this file and head back to our terminal, and let's now run this server. This command runs our Python script inside the virtual environment using UV. So that's all for our MCP server, and now we need to connect it to Cloud for Dist. 9. 2.6 Connect Server to Claude Desktop and Test Your Server: Hi, everyone. Welcome back to the AI language. Today we are building an MCP server that can execute commands on terminal on your local MacBook. This means you can ask AI apps like Cloud for Desktop to run commands on your computer and send back the output, just like using a terminal, but through AI. Here's a preview of what we'll actually test at the end, and it's absolutely amazing. Let me tell you that. And what I've done is basically, can you create a directory called Cloud output? Make a file inside it called terminal Underscore server underscore test dot DHT. And then it says, I'll help you create a directory and file as requested. So let's ask Cloud. Can you open this using code? The terminal server test doTXDFle. And let's before that, add some text. So can you add the text? I successfully made my first MCP server to this file, and then can you open this using code? The terminal underscoe server dot DF. So let's send this message. So here you have it. So, guys, isn't this amazing? You know, you have made actually an MCP server that can actually run terminal commands, and you used a large language model on an app, which is your MCP client, the Cloud desktop app, and you actually controlled your computer by creating a file, adding some text to it with the Smiley, and then opening it in code. Before we begin, if you enjoy learning about AI coding and automation, please like this video and subscribe to our channel. It really helps us bring more tutorials your way. Just a quick overview of MCP again. MCP stands for model context protocol. It is a system that lets AI, your Large language models hosted on apps like Cloud Desktop, IDs or Tools or any other app, and you can build your own app as well over here, which is called a MCP client. And this helps this AI interact with external tools and fetch information. And this is done through MCP servers. The servers do basically three kinds of things. They can provide resources or data and files, et cetera. So that's one primitive. There's another primitive which is called tools, so the servers can run or execute commands or actions on the behalf of the Large language model. So that is called the second primitive, which is tools. And the third is that the server can actually provide sample prompts to the Large language model to help guide its behavior. And that the prompts are the third primitive. Today we are going to focus on tools and we're going to build an MCP server that basically exposes a tool that the LLM can call from the app, which is going to be Cloud desktop, which is going to be MCP client, our server is going to then execute that particular terminal command. So it'll be a shell command that is going to be executed on the terminal and send back the output to the ****. As a first step, let's install this client, you can do that by searching for Cloud desktop. And let's search for that and let's click on Download over here, and you get to this website for downloading it, and just click on MacOS because we are on MacOS, Windows folks can actually use the Windows ink over here. So let's wait for a minute for this to download. Alright. So once it's downloaded, let's just open this and drag Cloud to applications over here. Now launch Cloud by typing Cloud over here and press Open. Let's click on open. So now you need to log in. So let's login with Google account. So if you're using Cloud for the first time, you need to enter your full name. All right. So once you've signed in, you'll see a welcome screen like this. Good afternoon, the A language. And we have the clot 3.7 Sonic model over here. This is the desktop app for Cloud for MacOS, and it'll give you 40 messages for free per day, so you don't need to actually pay initially to do this tutorial. Alright, so the next thing that we want to do is to install Python. So if you already have Python installed, you can check for the version over here. You can type Python three dash version. And for example, we have 3.9 0.6, but we need 3.10 or. So what we need to do is we need to install Python for MAC, and you can actually follow this video on our website, which is install Python on a MacBook. If you're on Windows or Linux, you can follow a similar, you know, steps from the website for installing Python. So to install the latest version of Python, we can open a new browser window and say, install Python. And let's go to the download Python page over here. All right, so let's click on download Python 3.13 0.2 and let's wait for the download to complete. So once this is completed, you can actually open this and you get an installed Python window like this. There's an introduction. Let's click Continue. There's a Read Me over here. So let's continue over here. And there's a license, I'm going to accept it. I'm going to use the standard installation and not going to customize for now, and let's enter a password. And this is not going to install Python for so we have Python installed now, Let's move the installer to the bin. So this is going to actually open this Python 3.13 folder over here and it's going to show you all the things that are installed, including the IDLE. Now, let's go back to the terminal. Let's type which Python three, and this shows you that this is installed to user local Bin Python three, so we can now type Python three version. And we see that AA Python three is now 3.13 0.2. This actually satisfies our version requirement for 3.10 and higher. We're good with this now. Now, next, we want to install UV, which is a fast package manager for Python that helps us install and run dependencies. So to install that, we're going to paste this command. And you can find this in the description. Press Enter. So let's wait for some time for this to get installed. All right. So there's a permission denied error, and you might want to then and we can see that the error is due to, you know, the ownership of local being with root. The local directory is inside our home directory, so we can actually change the permission over here. So use this command for this, enter your password. And then let's verify if the ownership has been updated. And yes, we can see that the ownership is now updated over here. So on this permission fail, you might be tempted to run this, you know, with sudo. But running with psudo might install this as root, which could cause permission issues later. So let's not do that, and let's update this permission like this. And let's not try to install UV again and see if it works. All right, great, so everything's installed. Let's source our environment file so that we can recognize the command UV. And let's type UV da dash version. And we can see that UV is now installed. This is the package manager that we wanted. If you're on a Windows machine, you can actually follow the install instructions on the UV page on GitHub Bastrl and if you scrolled on over here, you have the installation over here. All right, so now we are going to create the MCP directory structure. So MCP is our root directory and inside this there servers, and we might make multiple servers. For the current server that we're making, which is what we're calling a terminal server, we're going to make a new folder over here, and this is that directory structure. We also going to make a workspace directory so that all the work that Clouds desktop app does for us using our MCP server is done inside this workspace directory. So if it runs a terminal command to do something to create a folder, for example, or directory, it actually does it inside the workspace directory. So let's press enter now. Let's change to our terminal server directory. So just to reiterate, MCP will save everything related to MCP, including our server, which will be inside the servers directory. And there'll be a dedicated workspace inside the workspace directory over here. Each server will have its own folder. For now, I've just created one, which is terminal server. So now we are going to initialize a Python project inside terminal server. For that, we just type UV in it, and it's done that. Now let's create a virtual environment. So for that, we type UV, V and V, and let's activate it. Now, this creates a virtual environment which keeps our projects dependencies separate from the system's Python installation. Now we need to install the MCP package which allows our server to communicate with Claude. So for that, we'll do UV, ad MCP CLI and presenter. All right, so that's now installed. So now let's write the code to execute terminal commands. So first, create a new file terminal undersource server dot PY. Now, let's head over to VS code, and let's click on open over here. So we see the MCP folder over here that we just created, and we see the servers over here and we open our terminal server. So let's open this. So I'm going to trust the authors over here. And then let's go to our terminal underscore server dot PY file. So first, we are going to import the necessary code. We import the required libraries. Subprocess lets us run terminal commands, and fast MCP helps us set up an MCP server. The workspace directory is always set to MCP workspace. Now we are going to define the tool that's going to help us run the commands on the terminal. Let's break down this function step by step. This is a decorator, as we call it, and this registers the function as an MCP tool. This is what allows Cloud for desktop or any MCP client to call this function as an external tool. This entire thing over here is what defines the function. This basically means that the function expects a string input, which is the shell command that it needs to execute, and this will be provided by the Large language model as an input. And it's going to be a string, and the function will return a string back, which will contain the entire command's output or an error message which you can see over here. This is the line that runs the command on the terminal, and this is what resounds the output. We use a simple try except block over here to basically catch any errors that might happen. So if something unexpected happens, example, missing permissions, invalid commands, the error message is caught and returned as a string to your large language model, and then the large language model can basically take a decision. All right, so now we're basically going to start the server, and this starts the MCP server allowing Cloud to communicate with it. Let's save this file and head back to our terminal, and let's now run this server. This command runs our Python script inside the virtual environment using UV. So that's all for our MCP server, and now we need to connect it. Now we need to connect it to Cloud for Desktop. So let's open a new terminal, press Command N for that. So for that, we need to open the Cloud desktop conflict dot JCN file, which is located at this path, and we'll use Visual Studio code to open that and press Enter. This is a clod desktop configuration file. At this particular code in this file, this basically tells Cloud that there's a MCP server by the name of terminal, and it's located at this particular directory, and you can run it using this particular file using UV. In case you get some error in Cloud that you not able to connect to the MCP server, just provide the full path to the UV installation. Do that, go to the terminal and type which UV and you'll get the path where UV is installed. This happens because Cloud might not be able to recognize the command UV in its own environment, and so we provide the absolute path over here. Similarly, we provide the absolute path for our server directory as well. One more change would be to actually add a sync to the function definition over here, which is as per the practice followed on the Cloud website. Once you have done all this, you actually go to Cloud and quit that and then open Cloud again. When you open it for the first time, it might take up to 1 minute to load one or 2 minutes, and you might see plank screen till that much time. But now you see this hammer icon overhear and you click on this, it basically says that these MCP tools are available, and there's a run command tool. And when we go to our VS code, we see that this is the tool that we actually added. And then there's a definition over here which says run a terminal command inside the workspace directory and the arguments of the command, the shell command to run, and it returns the command output or an error message. And if you go over here, you can actually see that this is what the doc string that we had provided for our function over here. So now let's test this out. Alright. So it says, Allow the tool from terminal Local. Do you want to allow for this? So let's click Allow for this chat. And what I've done is basically, can you create a directory called Cloud Output, make a file inside it called Terminal Underce Server underscoetest dot TXT. And then it says, you know, I'll help you create a directory and file as requested. So let's ask Cloud. Can you open this using code? The terminal server test dot TXT file. And let's before that, add some text. So can you add the text? I successfully made my first MCP server to this file, and then can you open this using code? The terminal underscoe server dot DF. So let's send this message. So here you have it. So, guys, isn't this amazing? You know, you have made actually an MCP server that can actually run terminal commands, and you used a large language model on an app, which is your MCP client, the Cloud desktop app, and you actually control your computer by creating a file, adding some text to it with a Smiley, and then opening it in code. So please do subscribe to my channel. And like this video, if you found this helpful, I really find it amazing what all AI and large language models can do, and I really want to bring this to other people around. So please do subscribe because that helps me bring more tutorials your way. Thanks a lot for watching. 10. SECTION 3 START - Build Your Own MCP Client (Using Python + Google Gemini API) - 3.1 Quick Recap and: Quick recap, MCP servers, these are the folks over here. These are the back ends that expose external tools. MCP clients are these folks over here. These are the front ends that interact with the server and they send queries to the large language model over here and they process the responses, and then they can trigger and execute tool executions on the server. So today, we'll build a client that will basically connect to our previously built Python based MCP server. It will list the available tools like our terminal command executor and it'll send user queries to the Gemini API for process and it'll execute any tool calls through MCP server and display the final response. Before we start, let me show you an amazing preview of what I was able to accomplish with this MCP client connecting to my MCP server. And it's pretty amazing that you can actually use a remote large language model connected to your MCB client and your server and then give queries to your MCB client to actually run all the commands using your server. So here goes the preview. So once you run the MCP client, you'll actually get the welcome message which says connected to server with tools run commands. This means that our client has been able to connect to the server and get the available tools, which is just one tool over here, which is the Run command function which we basically use to run commands on the terminal. This output shows that we are in the chat loop and we can write a query. Let's ask Gemini to create a file for us and add some text to it. All right, so I've asked it to create a file MCP client success dot TXT, and at the text, I successfully created an MCP client with the Gemini API and connected it to my MCP server. And let's see what Gemini does with this. Okay, so as you see in the result, Gemini requests a tool call, which is run command, and the arguments are echo, I successfully created an MC client with the Gemini API and connected it to my MCB server. And this is basically written to MCB client success dot TXT, which is the filename that we provided over here. So this works pretty well, and then this tool would be executed and the response from the execution sent back to Gemini, which then reads and responds as I have successfully created the file and added the text which we had requested. So if I go to the Finder now, I can see that I have the MCP client success dot THD file over here, and I can just double click to open this. And it says, I successfully created an MCP client with the Gemini API and it connected it to my MCP server. 11. 3.2 How to Get Free Gemini API Key: Now, why are we using Gemini and not, you know, anthropic or any other model? Because you can actually go to aistudi.google.com and login through your Gail account and they're going to give you a Gemini API key for free. So there are some terms and conditions that you can check when you take this key, and essentially you can actually use it for free for testing purposes with certain lower limits and by allowing them to use your data while for training their mode. And this then makes it our ideal choice for this tutorial and experimentation. So I'm on astuditgg.com, and when I visit this site, it automatically gives me a prompt to get an API key over here. And otherwise, I think there's a button over here also to get the APK. So I'm just going to click on Get API key over here. Okay, so there's a code to test the Gemini API and there's a create APK button over here. So let me just use the API key from here. It's going to now generate the API key for me, and, you know, you should use your API key securely and not share them or embed them in code that the public can view. I'm going to disable this after the tutorial. For now, I'm just going to copy it from here and let it be visible. So to store our APIKeys securely, what we can do is we can go to the terminal and we can create a dot ENV file. Then let's open that file in Nano. And then let's paste our API key over here. And then before that, they're going to write Gemini, underscore, API, underscoe key, equal to. And let me add the I over here. And now this is basically an environment variable that I don't need to store in view in my code, and I can use this while developing my MCP client. Let's press Control X and save the file. And what we'll also do is that we'll add this file to Get Ignore Bluthytecho dot ENV, which is the file name in double codes, and then we write it to Get Ignore. So this basically prevents accidentally sharing our API key on places like Github or any other remote repository. 12. 3.3 Setup Project Directories, Files & Install Google-GenAI SDK: So first, let's set up our environment. So we need to create a new project and a virtual environment, right? So we go to the terminal, so you can open your terminal. So now we are in our home directory, and we can do a LS L and see that we had created a MCP directory over here last time. You can create this directory if you have not got this, and then we change to this directory. And you can see that we have two folders over here. One is for the workspace where our server can run all the commands so that we don't spoil anything outside this workspace. And the other thing is the server's folder where we had created our folder. So now let's create a client's folder over here. And let's change to the client's folder. Alright, so now we'll use UV in it. MCP client to actually initialize our project. So this command creates a new project directory called MCP client using the UV command line interface CRI tool. Now let's change to this director This has changed our current working directory to the newly created MCP client folder, and now we'll create a virtual environment. For that, we do UV V ENV and press Enter. And this basically is a virtual environment that will isolate all our project dependency so that they don't conflict with other projects. Now let's activate the virtual environment by typing source dot n BNS ACI. Activating the virtual environment ensures that Python uses the correct dependencies for this project. All right, guys, now we're going to install the required packages. And one thing that we're going to install is the Google GNI SDK for Python. How you do that is using PIP install Google GNAI. We're going to do UV add Google GNAI because we are using UV as a package manager. And the other two are the Python environment variables package python dot ENV and the MCP library as well. So what to do that, what we do is we say UV add MCP, then Python dot ENV. And then we add Google Jen AI, and we can make sure that we have matched the name correctly over here and then press end. I've already added MCP during the last tutorial on setting up MCP servers. I've already added Python dot NV as well, and Google GNAI, so it does that very fast for me. You can actually install it by typing this com. 13. 3.4 MCP Client Python Code Walkthrough: Alright, so now let's write the code for our clients. So we'll use touch client dot py. And this is going to create our Python file, and let's now open VS code. This is our server code from before. So what we'll do is we'll say File New Window. We'll go to file Open folder, and then go to MCP clients and MCP client and we'll open this code over here. Let me say I trust the authors, and let's open our client dot P file. All right, so this is the client dot PI code, and we'll go through it step by step. So first of all, on the top, we have all the necessary libraries like ASN IO OSS and JCN and these are used for ASN operations, environment variables, and system specific parameters and functions and for handling JCN data. All right, so next, we import the MCP client components, and this basically allows us to interact with external tools and execute commands like the MCP server. We use client session to manage our connection to an MCP server. We use SDD IO server parameters to define how we connect, and we use SDD IO client to establish communication. And now we import Google's Gemini, AI library and some helper types for function calling. So Gen AI is basically the main client for interacting with Gemini AI. Types helps us structure our AI generated responses and load ANV Loads our API keys securely. Next, we load our dot ANV file, so our script can access the Gemini APIKey. This ensures that sensitive data like our APIKey is kept separate from this code and not exposed in this script. Okay, so now let's create our MCP client class. This will handle the connection to the MCP server and communicate with Gemini AI. This is the MCP session for communication, and this is going to manage our Async resource then we have the Gemini API key that we store in this variable and check for its value over here for any errors. And then we configure the Gemini AI client by providing it with a Gemini API key. So this MCP client class basically manages everything from connecting to the MCP server to sending queries to Gemini. Inside the constructor, we retrieve our API key and configure the Gemini AI client. So next we define the connect to server function, and this is the method that basically connects to the MCP server and list all the available tools that are available with the server. It basically takes in the server script path. And if you recall from the last video, we had created a terminal undiscoe server dot P script for the terminal server, and that's basically what it'll take over here. Now, based on the extension of this script file, we might have a server written in Python or in JavaScript. So basically, we want to determine whether the server script is written in Python or JS, and this allows us to execute the correct command to start the MCP server. So in our case, the script path ends with PI, so we're going to take Python as the command. Then we define the parameters for connecting to the MCP server, which is basically the command and the server scribed path. And then we establish communication with the MCP server using SDD IO over here. And finally, we are going to extract from the transport object the read and write streams for the server. Then we initialize the MCP client session over here, which allows interaction with the server, and then we're going to send an initialization request to the MCP server. Finally, we request the list of tools from the session from the MCP server, and we will save it in the tools variable over here and then print a message for the user that we connected to the server with these tools, which is the tool names. In our case, for the terminal server, this is going to be the Run command tool which will allow us to run commands on the terminal. Now, MCP tools which are received from the server are basically in a certain format that we need to convert to a different format so that we can actually pass it to Gemini. And that is what we do using convert MCP tools to Gemini format, this function over here. Let's have a quick look at what this function does. So we have the function defined over here, convert MCP tools to Gemini and basically converts MCP tool definitions to the correct format for the Gemini API function calling. This basically takes in MCP tools as a list, which is basically a list of MCP tool objects with name, description and input schema. And it returns the list of Gemini tool objects with properly formatted function declarations. So we initialize a blank Gemini tools. And for each tool in MCP tools, we basically first, you know, run a clean schema function on the tool dot input Schema. This is basically going to remove some parameters which are forbidden for Gemini, which basically Gemini doesn't expect. And if you want to look at the clean schema function, we can go up over here, and this is the first step. So what we do do is that if it's a dictionary, we will basically remove the title if that is present inside it. And then we check if there's any nested properties, which is also a dictionary. Then for each key in that properties, we are going to again run the clean schema command. So basically removing title over here. And I did this because when I tried it with the title, I got an error which said that, you know, this title is basically forbidden inside this schema. So that is the clean schema part. So for each tool, we'll first clean the schema. Just to clarify, function declaration and tool are both imported from Google dot Geni dot Type. So these are basically what Google defines for proper function calling in Google's GEI SDK. And over here, while converting MCP tools to Gemini, once we have cleaned the schema, we basically use function declaration and tool, which are both provided by Google's GNAISDK and we first define a function declaration, which basically takes the name description and parameters and provides us with a function declaration object, and then we create a tool object using these function declarations, and then we append it to a list of Gemini tools, and then we return that Gemini tools list. That is what the convert MCP tools to Gemini does. In case you are going to use some other large language model, you might have to convert the tools returned from the MCP server to a proper format, which is expected by that particular large language model to implement function calling because all these models might implement function calling in a different way. All right. So let's go back to our connect to server function. All right. So here's our connect to server function, and we were on the last and now we basically have defined the function declarations for our MCP client class. So next, let's move to the process query function, and this basically processes the user query using Geminis API, and it will also execute tool calls if that is what is returned in the response from the Large language model API. And the arguments are basically a string query, which is the user's input query, and it will return the response generated by the Gemini model. Next, we'll format the user input as a structured content object for Gemini and basically we define the role as a user, and we basically define the parts, part of it, which is basically the query from the user and get the user prompt content. So this is one part of the content that we'll use. Next, we send the user input to Gemini AI, and we'll include all the vailable tools for function calling over here. So basically asking Gemini AI to generate content. We are defining the model as Gemini two point flasho one. And we are defining the contents as the user prompt content, which we basically defined over here. For the conflict, we basically provide the tools. Then we store the response in the response variable over here. So then we have these two variables, final text, which is going to store the final formatted response and the assistant message content, which is going to store the assessment response and we just initializing these two variables over here. And this is where we basically process the response received from Gemini. So again, this basically depends upon the response format that Gemini uses. So we basically process each candidate in the response and then each candidate has content parts. And for each part, we will check if the part is a valid Gemini response unit, and if it's a function call, this basically means that Gemini is suggesting a function to be called. So we want to process that. So we'll extract the function call details. So we'll store the function call response in something called function call part. This is a variable. And we'll get the name and the arguments that Gemini requested for the function call as tool name and tool arguments. And then we'll just tell the user that Gemini has requested a tool call, and then we're going to execute the tool using the MCP server. So we'll call the MCP tool with the argument. So we'll provide the tool name and the tool arguments, and we're using the session over here that we defined early on and then we'll await the response and store it as a result, and then we'll basically get the function response as result dot content. If there's an error, then we store the error. Now, again, we need to format this response of the tool call to a way that gemini understands, right? So basically create something called a function response part using types again, and we provide the tool name and we provide the response over here. Then we structure the tool response as a content object for Gemini over here. And we send this tool execution result back to Gemini for processing. So it knows what has happened over there in the tool call. So over here, we again provide the model. But now for contents, we provide the user prompt content which we provide for the first time. Then we include the Geminis function call request, and finally, we provide the tool execution results. So now Gemini has a complete context of what transpired, and we again pass the tools as well so that it can use it for continued use. Finally, we get the response over here, and then we extract the final response text Gemini after processing the tool call, and this is what is appended to final text over here. And finally, we return all the parts of the final text separated by a new line character, and this basically completes our process query function. All right, so then we have two more functions. One is the chat loop. So this is basically going to run a loop which expects a query from the user and it's basically going to process the query and get a response and print that response out. And this uses our process query function. We also have a cleanup function which basically cleans up the resources before it exits the program, and then we basically go to our main function over here. The main function basically initializes the MCP client and then connects to the server using the connect to server function that we went over. It then initiates the chat loop, expecting queries and processing all the queries from the user. And once the user basically types quit, it basically then quits the chat loop and breaks out. Finally, we run the cleanup and then exit the program. This basically completes the entire client dot P file that we 14. 3.5 Test Your MCP Client with Your MCP Server: Now you can actually go to the terminal. At the terminal, you can write Uv run client dot P and then provide the path to the server. Based on our directory structure, it's the parent directory twice, and then the servers directory and then the terminal server directory, and then the terminal server.p5. We've provided the terminal server PI path over here and we can press Enter to run this. So once you run the MCP client, you'll actually get the welcome message which says connected to server with tools run commands. This means that our client has been able to connect to the server and get the available tools, which is just one tool over here, which is the Run command function which we basically use to run commands on the terminal. This output shows that we are in the chat loop and we can write a query. So let's ask Gemini to create a file for us and add some text to it. All right, so I've asked it to create a file MCP client success dot TXT, and at the text, I successfully created an MCP client with the Gemini API and connected it to my MCP server. And let's see what Gemini does with this. Okay, so as you see in the result, Gemini requests a tool call, which is run command, and the arguments are echo, I successfully created an MCB client with the Gemini API and connected it to my MCB server. And this is basically written to MCB client success dot TXT, which is the filename that we provided over here. So this works pretty well, and then this tool would be executed and the response from the execution sent back to Gemini, which then reads and responds as I have successfully created the file and added the text which we had requested. So if I go to the Finder now, I can see that I have the MCP client success dot THD file over here, and I can just double click to open this and it says, I successfully created an MCP client with the Gemini API and it connected it to my MCP server. Isn't this amazing guys that we have created our own MCP client today, and we have connected to our MCP server. The MCP client actually runs with a large language model that's actually not local. It's on a remote Google Cloud and it uses the Gemini API to connect to the Gemini model. The Gemini model can actually receive the user query, understand what tools are available on the server, then request tool calls, and our client then actually passes that to the server, runs the commands that we need locally on our computer and gets the result and then sends it back to Gemini, which then responds with the final response message over here. You can quit by typing quit and press Enter, and then we have exited the MCP client. 15. SECTION 4 - Containerize your MCP Server Using Docker: Hi, everyone. So today, we are going to understand how to containerize our MCP server and deploy it using Docker and then connect it to Cloud desktop. So before we start, let me show you a review of what we'll actually accomplish with the help of an MCP server that is containerized using Docker and connected to Cloud desktop. So now let's go through the Cloud desktop conflict dot JCNFle. So over here, you have a terminal server, which is just one server that we have under MCP servers, and there's a command that is Docker, and this basically tells Cloud to use the Docker command line interface to launch your MCP server. Then you have a list of arguments. So this is a full set of arguments passed to the Docker command. So now we have Cloud opened up, and we see that we have one MCP tool available over here, when we click this, it says that you have a run command the run terminal command inside the workspace directory, which is the description that we have provided in the terminal server PY file. And if a terminal command can accomplish a task, tell the user you'll use this tool to accomplish it, even though you cannot directly do it. So this is basically an instruction for Cloud, and then you have the argument, which is the command to run, the shell command to run, and then basically you have the command output or an error message that is returned back. So Cloud does see the Docker container with the server available, and now let's try to test it out. All right. So I'll ask Claude to create a file called MCP Docker serversuccess dot TXT, and at the text, I successfully built a Docker container with an MCP server and tested it. So let's see what this does. All right, so it says, Allow tool from terminal server local to run, and I'll say allow for this chat over here. And then says, I'll help you create the file using Run Command tool. And then it's always run the command is asking you to view the result. So let's check this out. So the command it ran was echo and then the text that we gave it, and then the file name. So it looks good till now. And let me verify the file was created correctly. So it says view result from the run command from Tamil server, so it actually then runs the cat command for this particular file and it gets this output. And based on that, it says the file was created successfully, and it has the specified text. So is there anything else I can help you with? So that's all that we wanted Claude to do. And now let's check this out for ourself as well in in our local directory on our MacBook to see whether that's actually reflected in the mounted volume or not. Alright. So I have my finder open. Let me open the workspace directory. All right. And you can see that, you know, I have this MCP Docker server success dot TXT over here, and I can open this. And it has a text that was provided that I successfully built a Docker container with an MCP server and tested it. And you can see now that we have put our server inside a container, and we're using that with Cloud desktop. That basically helps us isolate our MCP server code from the environment that it's running on. All right. So before we begin, a very brief recap of what is Model Context protocol. So MCP or Model Context Protocol is a new standard that enables AI applications like Cloud desktop to interact with external data sources and tools through what we call MCP servers. It operates on a client server model where MCP clients embedded in your AI app send requests, and MCP servers perform the requested tasks. Whether that's accessing a file system or managing repositories or invoking specialized tools. However, deploying these MCP servers directly on your host system can be a real headache because you'll face issues like dependency conflicts. Different tools require specific versions of programming languages or libraries. The complex setups installing and configuring the server environment manually is time consuming. And is a lack of isolation. So running the server directly on your host risks exposing your system to unwanted access or conflicts. So this is where Docker comes into play. And if you go down, you can see this nice infographic on their website. Docker packages these servers into containers which encapsulate all the dependencies and isolate the environment, ensuring consistency across different platforms. Tools such as Docker Desktop, Docker Hub, Docker Scout and Docker Build Cloud work together to streamline development testing and deployment. So now, essentially, you have the client, which is connecting with MCP servers that are contained inside their own container along with their tools. Alright, so let's go to our terminal server code. And we have written this code last time, and we see that we have a terminal server directory inside which we have the terminal underscore server dot p file, which basically has a run command and this tool is an MCP tool defined using this decorator over here. And what this basically means is that your MCP server recognizes this as an MCP tool that can then run commands on the terminal as requested by the MCP client, and it then returns the output from running the command or the error, whatever the case may be. If there's an exception, we cache that and then return the exception text as a string. So that is what this server is all about. And let's also head over to the terminal and check our directory structure. So as you know that we created a directory called MCP in our home directory. And if you do an LSL, you'll see that we have three folders, clients which holds our MCP client that we built in one of the other videos, and the servers folder which holds the terminal server that we built and are going to use in this particular video and a workspace folder, which is the workspace for our server to run all the terminal commands. And this is basically to ensure other files in our file system don't get affected by this tutorial. Next, we need to download Docker. So let's search for Docker Desktop download and click on the docker.com link, which is the official download website, and let's scroll down. And you'll find this link to download Docker Desktop. Let's hover on this button and you'll see the options over here. Please download it for your system. I'm going to download it for Mac Apple Silicon. Let's wait for a minute for this to get downloaded. All right. So I already have it downloaded from before, and once you get it downloaded, you'll have a DMG file, which you can just double click and then drag the Docker application to the applications folder over here and leave it over there. So I already have this installed, and then I'm just going to open this from the application go to the applications folder from here, look for Docker, and then double click to open this. So once you have this open, you can sign in. Otherwise, you can actually skip by clicking over here. And now you have your Docker desktop open, and in case you have some previous containers, you might see them over here. All right. So first, we need to create a Docker file to containerize our custom terminal server. So let's change our directory to the terminal server folder, and let's create this Docker file. Now let's open this Docker file in VS code, all it. So here we have our Docker file. So this is going to be our Docker file, and I have added commands to describe what is being done in each of the lines, and we'll just quickly walk through this to understand how this works. So we are going to use the official Python 3.11 slim image as the base image for our Python. And this basically ensures that we have our Python en which is above 3.1, which is required for MCP. Then we set the working directory inside the container to slash app, and we copy all the files from the current working directory on our host machine to this app directory in the container. This will happen when we run this talk of file. So our entire code will be transferred to the container. Then we install any required Python packages from requirements store TXT. We export the code 5,000 so that the container can accept incoming connections, and unless you have some reason to change it, you can leave it at this and then we finally defined the command for the docker to run our server, and that would be Python and then terminal underscore server dot PI. And it basically starts our custom terminal server when the container launches. So that's it. A simple docker file for us. All right. So now what we need to do is we need to create a virtual environment. And just in case you have been following from the previous videos, you would already have this created, but if not, you can create it by simply type CD MCP servers terminal server to change to the directory and then typing Python three VnV which basically creates a virtual environment in this particular directory. And now you can activate the virtual environment by typing source dot nv Bins Activate. And now you can install MCP in this virtual environment by typing PIP install MCP, and then you can actually write all the requirements to the requirements doTXD file by typing PIP frees requirements dot TXT. Let's head over to VS code and check out our requirements to TXT file. And this is our requirements TXT file, and we see that we have MCP over here. And this is needed by Docker to install all the requirements in the Docker container once it's run. All right, so now we are going to build the Docker image, and for that, we'll use the Docker build command. The Docker build commands basically builds the Docker image. The T terminal server Docker tags the image with the name terminal server Docker. The dot basically specifies that the current directory containing the Docker file is used as the build context. Let's press Enter. This might take a while to build. Let's wait for it to install and download everything that's needed. It's time to integrate it with Cloud desktop. So this configuration tells Cloud desktop how to invoke your custom MCP server via Docker. And this is basically the same config file that we have updated earlier for our server without first first, you need to open your Cloud desktop confictt JCN file, and you need to locate this in your system, but it's generally located at this place on a MacBook and let's press Enter. And this basically shows us the last used Cloud desktop config dot JCN and we see that the path is correct. Over here. Next, we need to replace the existing terminal MCP server with the new definition that uses the container. All right. So now let's go through the clod desktop confit JCNFle. So over here, you have a terminal server it's just one server that we have under MCP servers, and there's a command that is Docker, and this basically tells Claude to use the Docker command line interface to launch your MCP server. Then you have a list of arguments. So this is a full set of arguments passed to the Docker command. So you have run, this is going to start a new container. You have I, and this basically keeps SDD IN open. It is needed for Claude to send, receive messages via SDD IO. And then you have dash RM, and this basically tells Docker to remove the container automatically when it exits. This keeps your system clean, so no leftover containers after each use. And then you have Dasdash in it, which basically adds a minimal in it system. Have E Docker container equal to true, which basically sets an environment variable, Docker container equal to true inside the container, and the MCP tool or server basically could check this and behave differently in a container environment. Then you have V, and this basically is a volume mount. So the left side uses the AI language MCP and workspace. This is basically a workspace directory, and this is the host directory. And what we want is we want to mount it to a certain directory on the Docker container. So now for this, what you can do is you can actually go to terminal server dot p. And you can check this out that we had used A tilda for the home directory, slapAS Workspace as the path that your script expects. This is basically going to translate to slash root slashmCPlash Workspace in the world of Docker containers. So instead of writing users and your username, you'll need to specify slash root slash MCP slash Workspace. And this is then going to basic map both of them or mount your host volume onto the Docker container. So now the container has access to your real workspace files. So for example, when your terminal server runs a command like shoot slash MCP slash Workspace, it's actually listing files from your local MAC folder. Finally, you have the Docker image name, and it's basically the one that we had built earlier using the Docker build command. So this config looks great, and we've already checked that this config is located in the Cloud directory. Now what we can do is we can actually go ahead and launch Cloud. If you already have Cloud launched, please do close it and then right click on the icon to quit it so that you have completely closed it, and then you can reopen by clicking it over here. All right, great. So now we have Cloud opened up and we see that we have one MCP tool available over here. When we click this, it says that you have a run command, which is a run terminal command inside the workspace directory, which is the description that we have provided in the terminal server PY file. And if a terminal command can accomplish a task, tell the user you'll use this tool to accomplish it, even though you cannot directly do it. So this is basically an instruction for Cloud and then you have the argument, which is the command to run, the shell command to run, and then basically you have the command output or another message that is returned back. So Claude does see the container with the server available, and now let's try to test it out. All right. So I'll ask Claude to create a file called MCP Docker serversuccess dot TXT, and at the text, I successfully built a Docker container with an MCP server and tested it. So let's see what this does. Alright, so it says Allow tool from terminal server Local to run, and I'll say allow for this chat over here. And then says, I'll help you create the file using Run Command tool. And then it's always run the commands asking me to view the result. So let's check this out. So the command it ran was echo and then the text that we gave it, and then the file name. So it looks good till now. And let me verify the file was created correctly. So it says view result from the run command from Tamil server, so it actually then runs the CAT command for this particular file, and it gets this output. And based on that, it says the file was created successfully, and it has the specified text. So is there anything else I can help you with? So that's all that we wanted Claude to do. And now let's check this out for ourself as well in our in our local directory on our MacBook to see whether that's actually reflected in the mounted volume or not. Alright. So I have my finder open. Let me open the workspace directory. All right. And you can see that I have this MCP Docker server success dot TXT over here, and I can open this. And it has a text that was provided that I successfully built a Docker container with an MCP server and tested it. And you can see now that we have put our server inside a container, and we're using that with Cloud desktop, and that basically helps us isolate our MCP server code from the environment that it's running 16. SECTION 5 - Simplify client code with LangGraph & LangChain: Hi, everyone. Today we are going to make an MCP client using Lang Chin MCP adapters. Langchin makes it very simple to build your own MCP client, and I'm going to cover all the steps to make the MCP client and connect it to the Lang graph agent. So before I start, let me give you a 1 minute preview of what we are going to achieve today with the Lang chin MCP client. Trust me, it's pretty amazing that you can use Lang chains MCP adapters to do a very simple implementation of a client and connect to the Gemini API with all the tool calls. And all this can be done for free because Gemini provides you a free API key. So here it goes. So we're going to ask our MCP client make a file and add some text to it, and let's see how that works. Let's press Enter. All right. So this means now our MCB client has started. Let's provide a query. So let the query B make Langhin MCP client or TXT and add the text I made an MC client with Lang chin successfully with Smiley. So let's press Enter. Right, so you can see the response over here and we have the human message which says make file Lang chain MCP client or DHT. And this is basically the query that we sent. And then we have an AI message which has no content. Then we have a tool message, and this would have been a tool call. You can actually just directly print the response to see more details. I'm just printing out the content over here using my custom encoder. And then finally, you have the AI message with the content which says, Okay, I have created the file Lang chain CP client dot TXT and added the text you provided anything else. So let's just check this out now. Let's go to find a and I have my MCB directory open over here. I'm going to go to my workspace, and I see I have Lang chain MCB client dot text, and you can see that it has added the text that I asked for, and this works amazingly well. All right, so a quick recap of what MCP is. So MCP starts for model Context protocol, and it basically provides a way for large language models to connect with external tools and services. There are a few basic components like MCP servers which provide context tools and prompt the clients. For example, you can have an MCP server with a tool to add or divide numbers, and it can also provide resources like data. There are MCP clients, and the clients maintain a connection with the servers inside a host app, and there are clients you can make in Python. You can use the Cloud desktop app as a client, and we are going to build our own client in Python today using Lang chains MCP adapters. MCP clients can actually request the servers to call or execute tools and provide the results client. The clients connect with the lag language model over here, we're going to use the Lang graph agent, and the Langraph agent can actually use adapters to connect to this particular client and load the available tools, head back to the terminal and create an environment variables file by typing touch dot NV and press Enter. I already have this file over here, so I'm going to just open this using NanO and as you see, I have defined APIKsGemini APIKe and Google APIKe and I have pasted my key over here. You can actually write this line over here and paste your key next to it. I have used two environment variables, Google APIKey and Gemini APIKe because in my personal project, I like to use the environment variable Gemini APIKey. However, Lang chin expects the key to be present under an environment variable called Google APIK. Just to avoid any confusion and allow both of the variables to be used, I actually defined the key twice using two environment variable names. And you can do the same. For Lang chain, you need to use Google API press Control X and save the file before exiting it. So now you have your Environment file setup. So now we can create a virtual environment which basically helps us keep our project dependencies separate from all other work that we're doing on a computer, source dot NV slashBN slash Activate. And this basically makes you enter the MCP client Virtual environment. Okay, so now we are going to add some packages that we need to develop our MCP client. These packages are Lang chin, the Lang chin MCP adapters, Lang graph, Lang chin Google Gen AI package, the Google Genitive AI package, and the Python Environment package for the environment variables. After writing UV ad and the list of packages, press Enter, and I already have this installed, but it will take a few seconds or a few minutes to get this installed. And once this is installed, we are then ready to actually start writing our angchinmcp client dot PII. N type code and the file name, and this is basically going to open this in VS code. All right. So let's begin talking about the Lang chain CB client dot PY file and how this works. So I'm going to start with the imports over here, and we have some standard imports for Async operations, for accessing the environment variables, for command line argument processing and others. Then we import the MCP client related packages for session management and for server setup and startup. And this is used to actually connect to the MCB server. Now we have the ang chin agent and LLM imports. We have the load MCP tools. This is basically used to load the MCP tools correctly. Then we have the prebuilt react agent from Lang graph and we have the Google Gemini LLM wrapper from Lang chin. Finally, we load the environment variables using load underscore dot ENV from the dot ENV package. So these are basically all your imports, and now we can actually directly go down to the LLM instant we basically use the chat Google generative AI package that we imported and instantiating the LM is just as simple as using chat Google generative AI with a specified model name, so we're using Gemini 1.5 P over here. You can actually use two point oh as well. You have the temperature which we have set to zero for completely deterministic output. So basically, you can increase it for making the output more creative. Then you have the max retries, which is two over here, basically automatically retries the API calls up to two times to overcome any kind of errors. And then you have the Google API key. So Langhin basically uses the Google API key in one variable to load that key and provide access to the Gemini API. Okay, so over here, we're just checking if we have provided the right number of arguments to a Python script. Next, we have the MCP server parameters. We configure these parameters providing the command, which is Python and can actually have a server script that ends with PI for a Python script, and otherwise we assume that it's going to be a node or Jspace and we provide the server script path which we actually got through the Python program call over here. So then we have a global variable to hold the active MCP session, and we're going to use it with the tool adapter that we're going to look at when we go down the code. Okay, then we go down to the run agent function. This is our main function that does all the work. It basically opens a connection to the MCP server. It starts the MCP session, stores the session for tool access and loads these tools using the MCP tool. So you basically have your server, your MCP session, and your tools all started up over then it's going to create an agent and provide that agent with these tools. And finally, it's going to enter a loop requesting the user to provide a query and then invoke the agent asynchronously and print the response as a well formatted Jason. So just to repeat, we basically have the connection to the server. We have a MCP session setup. We have the tools set up, and then we basically create an agent with these tools and then process the user queries and printer response. This is basically all the steps we're going to do. And to do that, here is the code. So we basically get the read and write properties for the server using SED IO client and the server pattern that we defined above. Using read and write, we actually build the client's session and store it as session. We then initialize the session using session dot initialize, and then we use the global MCP client variable to a simple object that holds this particular session. Now we are going to load the MCP tools using the adapter from Lang chain. So this is basically a very simple implementation. If you've seen the previous video on implementation of an MCP client with the Gemini API, would know that we did a lot of conversions over there to manage the conversion from an MCP tools format to the Gemini format. But ang chin makes it easy by actually using load MCP tools, and we directly have a list of tools over here. Now, finally, we have the tools and we have the LLM that we defined at the top using the Google API key. We use that to create what we call a react angrap agent, which we store as agent over here. We print that we've started the MCP client and we can type quid to exit, and then we go into a loop and prompt the user for a query as soon as we get the query input, we actually produce a response by invoking the agent using the Asynchrons invoked function from Lang chain and providing the query to the agent. Since this agent already is aware of all the tools and the model that we are using, Lang chain provides us with the implementation of sending this request to Gemini, understanding the tool calls, and then executing the tools for us using these adapters, and it is that simple to then get the response. Finally, we format the JSON using the custom encoder we've defined on the top. You can have a look at it. It just basically prints the output in a well formatted fashion, and this completes our run agent function. So that's a simple explanation of the entire code. And again, if you've followed from the previous videos on creating the MCP client without using Lang chin, you can see that this is much, much simpler, and that's one of the key advantages of using Lang chain over here. Now we can actually test out this agent by heading over to terminal. So we have named our client file Lang chain MCP client dot PY, so you can type UV run and the client file name, and then you provide the Python or the Javascript server file name. So for our situation, we actually go to our servers folder that I just showed you at the beginning and go to the terminal server and terminal server dot PY file over the terminal server has the ability to run commands in your terminal. So we're going to ask our MCP client to make a file and add some text to it and let's see how that works. Let's press Enter. All right. So this means now our MCB client has started. Let's provide a query. So let the query B make Lang chin MCP client or TXT, and add the text I made an MCB client with Lang chin successfully A with Smiley. So let's press Enter Right, so you can see the response over here and we have the human message, which says make file Lang chain MCP client or DHT. And this is basically the query that we sent. And then we have an AI message which has no content. Then we have a tool message, and this would have been a tool call. You can actually just directly print the response to see more details. I'm just printing out the content over here using my custom encoder. And then finally, you have the AI message with the content which says, Okay, I have created the file Lang chain CP client dot TXT and added the text you provided anything else. So let's just check this out now. Let's go to find a and I have my MCB directory open over here. I'm going to go to my workspace, and I see I have Lang chin MCB client dot text, and you can see that it has added the text that I asked for, and this works amazingly well. So this is how you can create an MCP client with Lang chin. Basically, it provides wrappers for all kinds of AI models and for the MCP connections, which help us simplify the implementation of the code a lot. And you would notice this if you have actually seen the video of building your MCP client without Lang chin and this particular video of building with angin. 17. SECTION 6 START Build MCP Client with Multiple Server Support: 6.1 Introduction: Everyone. Today, we are going to make a Lang chin based MCP client which supports a JCN config for multiple servers. And so we can actually provide a file like the AI language underscore config dot JCN which can actually specify multiple servers, similar to what you have for clot desktop. But this time we're going to make it on our own using Lang chin or Lang graph for the react agent, and we are going to use MCP and Google Gemini API for the large language model, and we're going to do this in Python. 18. 6.2 Let's look at the config.json file: So let me just show you the sample conflict dot JCNFle that I'll use. Over here, we'll have two MCP servers defined. One will be the terminal server that we have previously built in this course, and the other will be a pre existing MCP server, which for now, I'm using as fetch. You can choose any one of the MCP servers, and I'm going to actually use the Docker command to run both these servers. And we've already looked at how to build a terminal server and put this in a Docker container and then use it with your own client. 19. 6.3 Demo - MCP Client with Multiple MCP Servers: Before I start, let me show you how this works. And for that, I'll head over to the terminal. So let me change to our MCP directory, then to clients, then to MCP client. Then let me run our Lang chain MCP client with conflict PY. This is going to start our MCP client. And as you can see, it basically connects to the MCP server terminal server, which is our first MCP server, and it loads the tool run command. And this basically allows the MCP client and LLM to run commands on the terminal on the local host machine. And then it says, I've loaded one tool from terminal server. Then it connects to MCP server fetch. This is the pre existing reference server from the model context protocol Github and it loads the tool fetch, which can basically fetch content from a URL, and then it says, I've loaded one tool from fetch. And then it says the MCP client is ready and then type quid to exit. So let's ask the client first what all tools are available to it. All right. So what tools do you have available to use? All right. So to this query, basically the responses that I have access to the following tools. Run command to run terminal commands and fetch to fetch content from a URL. Now, let's provide a query to fetch content from a Wiki URL and then summarize it and write it to a file using a terminal command. All right, so we'll write the query. Can you fetch content from the Wiki page for airplanes, first few lines, and write a summary of the content to a file called airplanes dot TXT. Let's press Enter and see what happens. All right, so I explicitly specified the Run command tool over here since Gemini seems to not recognize this while writing the content. Okay, guys, now this is the response that I've got. So there is the message that we sent, and then we have the tool message which says contents of the Wikipedia page on airplanes. And then it says that you can actually call the fetch tool with a start index of 500 to get more content, and then it does that. It says that the content was truncated. I will fetch more content to provide a summary. And this is more content. And then again, there's a new start index, and then there's again, more content. And then seems there was a connection issue and it could not fetch more. So it says I was unable to fetch the entire content of the Wikipedia page due to truncation and connection issues. However, I have the first few lines and here's a summary fetch for the fetch content. And then at the end, it says that I will use the Runommand tool to save the summary. And then I fetched the first few lines from Wikipedia page for airplanes and created a summary of the content, and I've written this to a file called airplanes dot THD using the Run Command tool. So let's go to the finder and check this file out. So here's the file airplanes dot HD in our Workspace directory. And if we direct click to open this, we can see that there's a summary of content, whatever it was able to fetch over here. So an aeroplane is a fixed wing aircraft propelled by a jet engine, propeller or rocket engine. They come in various sizes, shapes, and wing configurations, and are used for recreation, transportation, military, and research, and so on. So it seems to be that it has actually written a summary of whatever content it could fetch from the Wikipedia page and written it to a file using both fetch and the Run command tool. So this is pretty amazing. Now we have our own MCP client, which basically works with the Google Gemini API, and it can actually connect and initialize servers based on a conflict dot cN file just like Cloud desktop, and then use the tools to perform actions using the react agent from LangrapT makes a client more robust with this added functionality. 20. 6.4 MCP Client (with json config) Code Walk Through - Part 1: Alright, so now let's walk through the code for this client with the confit. So the name of the file for this client is Lang chain MCP client. Wconfg dot py and W Config basically stands for W ConfiC. This code implements a Lang chain MCP client that loads a configuration from adjacent file specified by the AI language config environment variable and connects to one or more MCP servers defined in this convic. It loads the available MCP tools from each connected server and then uses the Google Gemini API via Lang chain to create a react agent with access to all the tools, and then it runs an interactive chat loop where user queries are processed by the agent. Now this client builds up upon the previous client that we built on Lang chain ncpclientPY. So in case you've not gone through this particular code, please do that by looking at the previous video. All right. The first thing is that this client uses the AI Language underscore config environment variable to specify the path for the AI language conflict dot JCN file. If that path is not set, it uses the default file available in the code root directory, the AI language underscore conflict dot JS. Now if you scroll down, we have the regular imports that we have. We have our custom encoder. Then we now define a read conflict JSN function, and this basically reads the MCP server config Jason. And again, it tries to read the path from the AI language environment variable, and if not self, it falls back to a default file, the AI language conflict or Jason is the same directory as the code. And it returns a dictionary past JSN content with MCP server definitions. This is the attempt to read the environment variable. And then if this is not set, there's a fallback to get the script directory, and then join the file name with the script directory to get the actual file path, then it opens the path, whichever it gets, either the environment variable or the default path, and it returns the JSN that it's loaded from there, we handle exceptions to print an error message and exit. Then we instantiate the Google Gemini LLM. One difference over here is that we are using Gemini two point oh flash and there's a reason for this. 21. 6.5 Why Choose Gemini 2.0 Flash and not the Pro Models: Reason is that you can actually go to atudiogogle.com and login with your Gmail account, and then you can check out the different models over here. So Gemini two point oh flash has a request per minute rate limit for 15 requests per minute. If you were to look at some of the pro models like Gemini 2.5 Pro Experimental, it has just five requests per minute. Now, this is also the case with 1.5 P, which has two requests per minute. This is too low for an agent execution which might need multiple calls per minute, but we don't expect to go over 15 requests per minute, which is provided by Gemini two pinto flash, so we are good with this particular model selection. So that's one difference from the previous client, and then we have the Google API key which we load. 22. 6.6 MCP Client (with json config) Code Walk Through - Part 2 (continued): Have the run agent function which connects to all the MCP servers defined in the configuration, loads the tools, and creates a unified react agent from Lang graph, and then starts an interactive loop to query the agent. This is unlike the previous client implementation where we just had one server that we were connecting to through a Python script. So we basically first read the confit. Then we basically get the MCP server definitions from the confit, and if there are no MCP servers inside it, then we basically print an error message and we then define and initialize an empty list to hold all the tools from the connected servers because we want to unify them into one single list. And now basically using this ASNcEit stack to basically manage and cleanly close multiple ASYnc resources, we iterate over each MCP server defined in the configuration. So now we basically have the server name and the server info in mcpservers dot IM. So we have loaded the MCP servers from the confit file, and let's look at the confit file once again to understand this. So MCP servers has these items, item number one, and item number two, and each item has a server name and then it's information in terms of command and arguments. So now, basically, you get the server name, which basically corresponds to either terminal server or fetch and you get the server info, which basically corresponds to all the information that we have noted against it, the command and the arguments. We then print that we're connecting to MCP server with a specific name and then we create the STDIO server parameters using the command and arguments specified for the server. So we'll specify the command, which in this case is going to be Docker for both. And then we specify the arguments like so, and for Docker, we basically use the Docker image file over here. So this basically gives us server params, which we are then going to use to establish an STD IO connection to the server. So we use the server parameters and then we get the read and write stream objects for this particular server. So we are looping through each server. So for one server at a time, we do all these steps. We then use the read and write parameters to create a client session, and then we initialize the session, and then we load the MCP tools into server tools. And for each server tool, we'll basically inform the user that we have loaded the tool with a specific name, and then we append it to our list of unified tools. Once we are done with all the tools for this particular server, we'll say that we have basically loaded tools from this particular servers, and we'll use the length of server tools to denote how many tools were loaded. Then the four loop continues for the next server, and this way we load all the tools into a single unified tools list that we are then going to pass to the agent. All right. So then we have some basic error handling, and after that, we basically create the agent, which is a react agent from Langrap and we provided the LLM, which is the Google Gemini LLM instantiation that we did above along with the unified list of all the tools. Then we start an interactive chat loop like we did for our previous MCP client, and this expects a quick statement to quit the loop. Otherwise, it basically invokes the agent with the query provided by the user and then prints the response. And then, of course, we have the entry point over here. All right, so that's all about the code for the ankchin MCP client with the JSON confit file. 23. 6.7 How to use existing MCP servers from MCP Github (example uses "fetch" server): Now let's look at the config file itself. Now, you would remember terminal server from the previous videos in this course, and we have used this previously with the Lang chin client without the config. Now we actually add more servers to this, and for this, I have used a preexisting server just to check out my implementation of the MCP client with the config. For this, you can choose any specific server you want. What I have done is I have searched for the MCP servers list and then gone to the Github page. And over here, you have several MCP servers. I have chosen the fetch server from here, which basically can fetch web content because what I aimed at making as a demo was to fetch content, summarize it, and then write it to a file using my own terminal server. So if you click on the fetch server, you can see that they have a Docker file, and they provide a configuration to add to Cloud using Docker, where the command Docker is used, and then they have the run command with the image name. So when setting this up, what you need to do is you need to first clone these servers. So we head back to the main Gu page for all the servers, and then we actually copy the clone command. I have SSH setup, so I'm going to copy the SSH clone command from here. You can open a fresh terminal window and you can go to CD MCP, and over here, you can actually make a directory for these reference servers. So you can actually clone the servers into a directory called servers Ref. I've already done that, and these are basically all the preexisting reference servers provided on their Github page. To do this, just type it clone and then paste what you copied from there and provide a name for the directory, which is servers underscore reef and then press Enter. I've already done this, so I'm not going to repeat it, and you can clone the directory like this to this particular folder. Note that we are doing this under our MCP directory, and this is going to make the servers underscore ref directory inside it. You don't need to create it separately. Once you have this created, you can actually shift to the server's ref directory. And then you'll find a SRC directory, which is a source directly inside it, and then you'll find the fetch directly inside it. Now I'm inside the fetch directory, and you can do an H L to list all the files over here, and you see that you have the Docker file over here. So before we can use this particular MCP server in our MCP client confit file, we need to build the Docker image. So for that, we can use the command Docker build. T which basically tags the image with a specific name. You can provide it with some names. Let me just check the name that I have used. I've used MCP Feed server test. I'm going to just copy it to demonstrate how you can build it and this is how you build it. Then you put a dot at the end to basically provide the current directory as built context and press ender. This is basically going to build the Docker image for you. Now your Docker image is built. And then you can actually go to the AI Language underscore conflict dot JCNFle when you specify this Docker image name, Docker understands that this is what you need to actually run. Of course, if you know from our previous videos, you need to have Docker desktop running in the background for which you can actually open Docker desktop by going to your applications folder and looking for Docker over there. Okay, so with this conflict dot JCNFle and with the Lang chain MCP client with config dot py file, we actually have our MCP clients setup, and now we can basically head over to the terminal to actually run this particular client and test it. 24. SECTION 7 START - Server Sent Events - MCP Server and Clients using SSE - 7.1 Introduction: So this is going to be pretty exciting because till now, we have been working with MCP servers that have been running locally on our computer. And as you can see in this particular infographic, that is what the general trend has been even with Claude Desktop as a client and Python or JavaScript servers which run on our computer. Now we have a chance to use server Sent events and build a MCP server which basically connects through an STDP connection. So today we are going to build our own MCP server, and we are going to use server sent events or SSE to build it and then deploy it on a URL and use that to connect our client to the SSE server, and we're also going to try and deploy this SSE server over the web to the Google Cloud platform for free, and we're going to try and connect our MCP client to this SSE server remotely. 25. 7.2 Quick Recap, What is STDIO and SSE?: Before we begin, let's understand the basics of what MCP is. Model context protocol is a way to allow structured and consistent communication between large language models that are hosted on clients, which we call as MCP clients. And a server which we call MCP server. There can be multiple servers, and the servers can expose functionality like tools where tools can provide some kind of extra functions that the server can perform for the Large language model. Then they can provide data sources. For example, over here, we have local data source A, local data source B, or they can provide access to remote services over the Internet, like we have remote service C over here. All right. So there are two main components as we just said. One is the MCP client, and this is the user facing agent or interface that sends the prompts, receives the responses from the Large language model. And handles the user interaction. This also integrates with the server and then sends any kind of requests from the large language model to the server, which then basically responds to your model inputs with actions, tool calls, data, et cetera. Now there are two ways MCP clients can connect to MCP servers. One is through SDD IO, which is standard input output where each client talks to its own server through standard input output. So there's basically one to one connection between the client and the server, and basically the client is given the path to the server file and it starts the server and then starts talking to. The other way is server sent events or SSE where multiple clients can basically connect to an already running server using a web based streaming protocol. With SSE, you can basically let your MCP clients connect to an already running server using a weblink and port, just like connecting to an API. It supports long lived unidirectional streams of data perfect for receiving model outputs in real time. On the other hand, SUD IO requires a fresh MCP server to be spawned for every single client. That means one server per client. 26. 7.3 Setup Directories, Clone GitHub Code (git pull only, if done at course start): All right, so let's set up our project directories first. So in your home folder over here, let's make the MCB directory. I already have this made. You can enter this command to make it. Then let's change to the MCP directory, and let's make three directories over here, one for all our clients, the other for our servers, and the third for our workspace. So let's make the servers directory and press Enter. Then let's make the clients directory. And press Enter, and then let's make a workspace directory, which we can use for any kind of files that our server creates or any kind of data that it needs to read. This will keep the remaining file system separate from our workspace, which basically avoids any kind of issues and risks. Okay, now we change to our servers directory, and we first check out the code for the server. Please use the link in the description to do a Git clone of the server code. And then this will basically make a directory over here, which is called terminal underscore server. I already have done that and I already have this terminal server directory. So this will basically give you the entire code for your server. Let's go to the parent directory and shift to the clients directory now. And then let's clone the Github code for our client. Once you do that, you'll have a MCP client directory, which basically has all the code for our client. 27. 7.4 Setup Virtual Environment and Dependencies: All right, so now we have Python and UV both installed, and we also have a Gemini API key from Google, and we have put that in the dot ENV file in our MCP client directory. Now we need to continue with the remaining setup by creating a virtual environment and installing the requirements. So for that, let's do that first for our client. So let's shift to the MCP clients directory and go to our MCP client. Then we write UV VENV and this basically creates a virtual environment like we do with Python MVNV. Then we activate this By typing source dot slash Bins Activate. Now we're going to open up Pi projects file and overhead, we specify the module that we actually want to build for, which is our client with SSE. We go back to the terminal and we can simply type UV PIP install dot to then install all the dependencies. This has installed all the dependencies that we needed for our client. Please note that you already have all these files and you just need to activate your virtual environment and then install the requirements using UV PIP install dot. All right, so I'm back to the home directory. Now let's do the setup for our server code. So we first head over to the server directory. So that directory will be MCP servers terminal server, and then SSE server because this is the directory that actually holds the SSE server code for our terminal server. Just to remind you, the terminal server is a server that can actually run commands using the shell on the terminal of your machine. Now we create a virtual environment by typing UV space VE NV. Now we activate this virtual environment by typing source dot n slash Bnlash Activate. Now we open our Pi projects file over here. And we just make sure that the Pi module is set to terminal underscore server underscore SSE. Now we head back to the terminal and we can type UV PIP install dot, and this is going to install all the dependencies that we need for our server. All right, great. So with this our server and our client dependencies are all installed. We have the code setup and we have everything else that we need to now start testing this. 28. 7.5 MCP SSE Server Code Walkthrough: Now let's go through the code for our server first, and you must have checked out the terminal underscore server code from our Github repo. And if you have not, you can do that using the link in the description. And inside that folder, we have an SSE server folder. You might see other files over here, including a Docker file, which is basically the simple server that we had made in our previous video. Now we go to the SSE server folder, and over here we have the underscore server underscores dot py file. This is our main server file, and this is what basically we are going to look through. We also have a Docker file which basically helps us continualize this server, and we'll use this to run our server later on. First, let's look through our terminal server underscores dot py file. I have this file open over here, and this basically implements an MCP server using the server sent events or SSE transport protocol. It uses fast MCP it uses fast MCP framework to expose tools that clients can call over an SSE connection, and SSE allows real time one way communication from server to client over STTP. This server uses starlet for the web server UCon as the AHGI server. Fast MCP to define the tools and the SSE server transport to handle the long lived SSE connections that you're using. Just to explain this briefly, ASGI stands for Async server Gateway interface. So it's basically like a middleman that defines how a Python web server like UVCon talks to a web app like Starlt. It allows Async input output, so your app can handle thousands of users, use web sockets and stream data like SSE. So this is what ASGI does. UVCon is the ASGI web server. It's the actual engine that runs your Python app. It listens for SEDPRquests, understands the ASGIPtocol and passes incoming requests to your app, which is Starlt or Fast MCP. It basically brings incoming data to your app and it sends back the responses to the browser. Starlt over here is the lightweight web framework, so it's a minimal ASGI web framework. And we use it to define the roots inside our app like slash SSE and slash messages that we are going to look at below. We use it to define the request handling logic as well and the middleware background tasks, et cetera. So this is the web framework that we're using, and all the connects to MCP, which is basically the language model communication protocol. MCP over here defines how the clients talk to the server what tools are available, how to send receive structured prompts, responses, tool calls, et cetera. And finally, we have SSE or server sent events, and this is basically a streaming HTP protocol. It's a one way communication server to client, and it's used for pushing updates, tokens, results in real time, and it's perfect for AI and model outputs. In this case, we're using it for connecting the MCP client to our MCP server over GTP and allowing the server to stream back results from the tool calls. So we basically have a MCP client slash agent in the browser which connects via SSE over SGTPT our server, which is the UVCon server, and this uses the ASGIPtocol bridge to connect to Starlt web app. The Sarlet web app handles all the logic, roots, et cetera, and basically connects with the MCP server that offers the MCP tools like Run command and and numbers, which we're going to look at below. So this is basically the visual representation of how our flow is going through. And now we go through the code. So we import our basic libraries and all the MCP libraries. So we have the core MCP wrapper to define tools and expose them. We have the underlying server abstraction used by fast MCP, and we have the SAC transport layer. We then import everything related to Starlight. So we basically import the web framework to define roots, import routing for SCDP and message endpoints through root and mount, and we import the SGDPRquest objects through request. Then we import UCon which is the ASGI server to run the StarLt app. And then we start with step one, which is basically initializing fast MCP instance, and this is basically our tool server. So we call this terminal, and this is our MCP server. We define the workspace as the home directory slash MCP slash workspace, which we've already defined in the previous steps. We then define our first tool, which is the run command tool, and the purpose of this tool is to execute a shell command on the terminal in our local machine and return the out we use the mcpt tool decorator to market as an MCP tool, and it's basically an ASN function that takes in a string, which is the command that we need to run on the terminal, and then responds with a string output, which is the output of the command or an error as the case might be. And this function is pretty simple. So we use subprocess to run this on the shell, and we return the STD SDD error, whatever the case might be. If there's an exception, we basically catch it and return the exception string over here. We then have the second tool which is add numbers, and it's also a simple tool to add two numbers and return the result. We again have the decorator to market as an MCP tool. And then this tool takes in two arguments, A and B, which is the first and the second number and it adds the two numbers and returns the sum, which is a float value, which is a sum of A and B. That's a very simple tool over there. Now we need to create the Sarlet app to expose the tools via STTP using SSE. We basically define this function called create Starlet app this basically constructs a starlet app with SSE and message endpoints. MCP server is the core MCP server instance, and we enable Debug mode for verbs logs, the full Sarlet app with all the roots. All right. So then we create an SSE transport handler to manage the SE connections. After that, we define a handle underscore SSE function which basically is triggered whenever a client connects to slash SSE. So this is the root that the client will connect to, and it will trigger this function. And what this does is basically it handles the new SSE client connection and links it to the MCP server. So how do we do that? We open an SC connection and then hand off the read and write streams to MCP. And then we return the starlet app with the configured endpoints. We have two endpoints. One is the slash SSE, which is for initiating the SSC connection, and then we have the messages endpoint, which is basically for post based communication, which basically is used when we create the SSE transport handler over here. Now we basically start the server using UVCon. So we first get the underlying MCP server instance from fast MCP into MCP server. Weiput RC pass, which is basically for passing command line arguments for host slash Port control. So we create a parser with a description. We then add the host and the port over here. We're using local host and we are using 80 81 as the port, and then we basically get the arguments from the parser. We built the Sarlet app using the create Starlet app function that we basically used earlier, providing it the MCP server, and we have the Sarlet app over here, and then we launch the server using UVCon by saying Uicon dot run, and we provide the app with the host and the port using the arguments that we just passed above. So in essence, if we go back to our visual representation, we have created a starlet app which when receives a connection over slash SSE, hands it off to the fast MCP server, which exposes the tools like ad numbers and run command. The Sarlet app also provides another route which is slash Messages, which is for post initialization communication, and the UVCon server basically runs this app using the ASDIPtocol bridge. So this was a quick overview of the code. But for now we are going to head over to our client code to just have a quick walk through of that before we start testing our client and server together. 29. 7.6 MCP SSE Client Code Walkthrough: All right, so this is the client underscore SSE dot PY file, and this implements the MCP client that connects to an MCP server using server Cen events or SSE transport. This client builds up upon the previous client that we built, which is client dot PI that uses SDD IO, and the only difference between the two clients is the difference between SDD IO versus SSE being used for communication. So let's go through the quote for the client. We first have some basic imports over here, which are self explanatory. You can actually read the commands over here to understand what these are being imported for. Then we import the client session from the MCP package, and this basically manages all the communication with the MCP server. We then import the SSE client helper, we then import the comperens from the Gemini SDK for AI based function calling and large language model integration. Over here, we are basically importing the main Gemini SDK module, Geni. This we used to configure the Gemini client and send prompts and get completions. So this is the core SDK entry point. Then we import the types. The types module contains important data structures used for tool and function declarations, generation configuration and structured prompts and response handling. Then we import from types the tool and function declaration. So this basically imports these specific classes which is used for function calling. The tool represents a tool that can be invoked by the AI model. Each tool tells the model what it can do, how to call the function, and what parameters are expected. The function declaration defines an individual functions name, description, and parameters. So we're going to use this below in the code. Generate content config is used to configure how the model generates content. We basically set the temperature and other details over here, and again, we're going to use this when we go down in the code. We then import the ENV file to load environment variables, and over here, we're basically storing the Gemini API key. This is a good practice to not expose your API key while you're actually using it in the code or you're pushing it to a get repository. If you remember we have added the dot NV file to get ignore. We then actually load the file after importing the required packages. We then have our main MCP client class with the initialization function that initializes the MCP client. So this constructor is basically going to set up the Gemini AI client using the API key from the environment variables, and it's basically setting up the placeholders for the client session and the stream context, which is going to manage the SSC connection. The Gemini client will basically be used to generate content and request any kind of tool calls from MCP server. This is a placeholder for the MCP session that manages the communication with the MCP server. These will basically hold our context managers for the SSE connection. So there will be a SSE stream life cycle that we need to manage the context for, which will be held over here and there will be an MCP session life cycle, which will be held over here. Now, we use the OS dot Get ENV function to actually get the Gemini API key. In case we don't find it, we raise a value error. And finally, we initialize the Gemini client with the API key, and this client is basically used for the communication. So next in the MCP class, we have the connect to SSE server function. So the steps that we perform are we open a SSE connection using the provided server URL. So this is the server URL that we're going to use. We use the connection streams to create an MCP client session. We initialize the MCP session which sets up the protocol for communication, and we retrieve and display the list of available tools from the MCP server. All right. So we first open the SEC connection using the SSE client and we store it in the streams context variable that we defined above. So the SSE client function is returning an Async context manager that yields the stream. Or the data channels for communication, and this is what we are going to store in the streams context. So we now get that data channel or streams using the streams context from above by entering the Async context. So streams is expected to be like a tuple like reader or reader and writer. That the client session can use. Now we create an MCP client session over here using the streams provided by the SSE connection. So we have the read and write streams, we use that to now create the MCP clients session, and the clients session object basically handles sending and receiving messages following the MCB protocol. Again, we get the session context first, and then we enter this session context to create the clients session. Now we initialize the MCP session by calling session dot initializes, and this basically sends an initialization message to the server to negotiate capabilities and start the protocol. All right. So now we are going to finally retrieve and list the available tools from the MCP server, and we basically print for the user that we are initialized the SSE client and we are listing the tools. And then we call session dot list Tools. And when we get the response, we get the list of tools from the response as response dot tools, and then we basically say, we are connected to the server with tools, and we print the tool name for each of the tools in the tools list. All right, so then we have a function which basically converts MCP tools to Gemini format. So the tools that we get from MCP have some fields or properties which Gemini does not expect, and we need to remove them. So we basically have a convert MCP tools to Gemini function. Let's have a quick look at this to understand what it does. This is a convert MCP tools to Gemini function, and I'm going to just scroll down to show you exactly what it's doing. It basically creates an empty list of tools and for each tool in the MCP tools that it has received as an argument, it's basically going to clean the schema for the parameters. What cleaning is done is inside the clean schema function. And if you look at the clean schema function, it is basically just removing the title key if it exists inside that schema recursively throughout all the properties. And that's it. That's a simple removal that we need to do because Gemini does not expect this title key if it exists in the schema. Now, going back to the convert MCP tools to Gemini function, after we have cleaned the schema, we just create a function declaration. That is how Gemini wants the function declaration to be. And if you remember, we imported this from the Google GNI SDK types. This is the type it expects for how to define a function, and we provide the name which is the tool dot name and the description and the parameters which have been cleaned to remove the title. Now we wrap the function declaration into a tool, and we assign it to a geminiTol object, and then we append this to the list of Gemini tools that we have and return this Gemini tools list from here. So this is all that the convert MCP tools to Gemini does. You can have a look at the function. It's pretty self explanatory based on all the comments that I have put over here. So we now get all the function declarations for the MCP client, and this basically completes the connect to SSE server function. Next, we have the cleanup functions. It basically cleans up the resources by properly closing the SSE session and stream contexts. So we basically need to manually call their exit functions, and this ensures that all network connections and resources are gracefully closed when the client finishes. And that's what we do over here. Now we have the process query function and this is a major function that does a lot of work for us to process the query given by the user. It basically uses the Gemini API to process the query and the Gemini API might request a tool call via function calling and if that happens, then the response is passed and the MCP server is invoked to call the tool. The result from the tool call is then sent back to Gemini for a final response. The steps that we follow are we format the user's query as a structured content object. We send the query to Gemini, including the available MCP tool declarations. And if Gemini's response contains a function call request, we execute the tool on the server, and then we send the response from the tool execution to Gemini. If GeminizsRsponse contains a function call, we send the result of a tool execution back to Gemini and then we get a final response, which is processed as text from Gemini. And then we basically get the final response from Gemini and return that the arguments are just the query string and that final response string is then returned as the return value. All right. Let's go through the code now. We create a gemini content object. It represents the user's query and this basically includes a role which is user, which basically says that this is coming from the user and the query is text wrapped in a part. The role and parts are provided to the content class, and this is basically then used to form the user prompt content. Then we send the query to the Gemini model. So we basically use generate content to do that. We specify the model, we specify the contents, which is just the user prompt content over here, and we basically generate the content configuration which we imported above. Over there, we provide the tools, which is based on the function declarations that we basically got from converting the MCP tools to Gemini tool definition formats. So we get the response over here and then we basically parse the response. Before that, we basically create an empty final text list to accumulate the final response text. Now for the response, we look at each candidate in response dot candidates, and then each candidate has content parts and we look for each part. And if the part is basically a function call, we extract the name of the tool and the arguments and we then tell the user that Gemini has requested a call to this particular tool with these particular arguments. And finally, we attempt to call the specified tool on the MCP server, and here we basically use the MCP session to call the tool with the name and the arguments. We get the result and this result is then put in function response. Or if there's an exception, we put the exception string inside the function response, and then we create a function response part where the response is the function response that we defined above, and we name it as the tool name. And this is basically the function response part. Then we wrap the function response part in a content object. Marked as coming from a tool. The role is basically specified as tool. Then we again call the Gemini API using generate content. We specify the model over here and in the contents, we now include all the three parts. We have the initial user query. We have the tool call that was requested and we have the response from the tool call. All three are included so that Gemini has the full context of what's happened and we give the function declarations again for continued use. Based on the response that we get, we basically again look at candidates content parts and text and we append that text to the final text over here. In case there's no function call that was required, we basically just use the text provided by Gemini and append it to the final text over here and we return this final text over here. So this basically is the process query function. Next, we have the chat loop. Chat loop is basically an interactive chat loop that runs in the terminal and it basically waits for the user input query. It prompts the user for the query. If the user type quits, then it basically breaks out of the loop. Otherwise, it uses the process query function to process the query provided by the user and awaits the response and then prints the response over here. Finally, we have the clean schema helper function that we've already looked at along with the convert MCP tools to Gemini function, which we also had a look at earlier. The last but not the least is the main function, which is the main entry point for the client. And this basically checks if this is basically invoked when we run the client Python script and it basically checks that the server URL is provided. It creates an instance of the MCP client over here. Then it basically tries to connect to the SSE server using the connect to SE server function, and then it basically calls the client chat loop and prompts the user for a query. And finally, it basically does all the cleanup that is required before exiting. And over here, we simply run this main function using the Async IO event loop by using asyncodt run and passing the main function over there. That's all for your client underscoresS dot PV function, and this is our SSE based client. 30. 7.6 Dockerfile Code (for MCP Server) Walkthrough: Also look at the Docker file that we are going to use for our terminal server. It's a simple Docker file and we basically use from Python 3.11 SLM, which is the official Python 3.11 SLIM image as the base image. We set the working directory inside the container to slash app. We copy all the files from the current directory in the local host basically to the app directory in the container. Then we install the required Python packages from requirements dot TXT. We expose the port 8081 so that the container can accept incoming connections. So basically, 881 is the port where we'll be able to access the MCP SSE server. And then finally, we use the Python command to run our SSE server, which is the terminal underscore SSE dot PY five. So that's all for the Docker file. It's a pretty simple Docker file to actually run this server. 31. 7.7 Test your MCP SSE Server and Client Locally: Alright, so now, let's go ahead and run our server first. So we can click here to open the terminal. So let's use the Docker build command, Docker Bildt to tag the image, and let's name the image terminal underscoe server underscore SSE. And let's not forget to put the dot for the built context and press Enter. This is going to build our Docker image with all the requirements, et cetera, and now this image is actually built. Now, let's run our server. Now let's run the container using Docker Run. The dash RM is going to help us clean up when the container exits. The P helps us match the local port to the container port. The V is a volume mount, and we are basically mounting the local host volume located at our workspace to root MCPs workspace inside the container. And then we provide the name of our image and we press Enter. And now we have a server running at local host 80 81. Now let's run the client. So we're going to click over here to open the terminal and we're going to use the command UV run. So we'll use UV run client unscos dot P, which our client file, and we are going to provide the URL for our server as local host codon 881 with the port slash SSE because that's the place where our server listens for initialization. Let's press Enter. And now it says initialized SSE client listing tools, and now it's connected to the server with tools run command and add numbers. So let's test this out. So let's ask Gemini to actually add two numbers. So I'm going to say add two numbers two and five using the tools, please, because it's a simple operation, it might just add it on its own. I wanted to use the tool and check if the server is running over that SSE connection or not. So let's press Enter. All right, so now we get the result that Gemini requested a tool call, add numbers with arguments A equal to two, and B equal to five, and the sum of two and five is seven point. So that's wonderful. Our server is now running over a HTP connection, and now we can actually go and deploy this server on the Google Clot platform and try to use this over a remote connection because there is still on our local machine on Local host. So I'm going to deploy this server on the web. Let's try to do that now. 32. SECTION 8 START - Deploying MCP Server to Google Cloud Platform - 8.1 Create a new Gmail Account (if: Okay, so first, let's set up a new Google account that we are going to use to create a project on the Google Cloud platform. So for that, I'll just simply search for create a new Google account, and I'll go to that. Let's click over here. And, um, as you can see, it says you can go to the Google account, sign in page and click on Create Account. So what I'll do is I'll open this in a new incognito window. Okay. And I'll con create account. And over here, I'm going to use for my work or for my business, and you can choose this accordingly. Since I'm going to be using it for an app, I'll choose for my work or for my business. Okay, and I'm going to go ahead with a Gmail address over here, or ask me for a first name or a last name. So just for this demo, I'm going to put the AI language and I'll put demo as the last name for myself. You can choose whatever is appropriate for you. Okay, and after filling in those, you know, details, it might provide you with these options. And for now, I'm following this format of using the AI Language dot Demo. So put in a Gmail address that you prefer and then click Next. Okay, and then we can create a new password for ourselves. And it'll verify your phone number as well. So, um, please put in your phone number. So I've put my phone number over here. Okay, so I have set up my Google account that I'm going to use. It does ask you for a little bit more information like your phone number or recovery email and all. So please follow those steps to set it up. And once you have your account set up for now, I'm going to use Not now to set up my business, right, and continue to use the Google account, right? So now I have this Google account set up, and I can use this for setting up my Google Cloud project. 33. 8.2 Create a Google Cloud Project: Okay, so now let's create a Google Cloud project. So we open a new tab and go to Google Cloud platform. And here we have it. Okay, and let's click on Sign in first. Let's click next. And a password. Alright, so now we have signed into a Google account, and we can actually click on Get Started for free. And All right. And to start for free with $300 free in credit, you need to click on Start free, but you will need a particular, um, you know, payments profile. Okay, now, since I'm recording a demo and it's not for an organization, I'll choose sing individual over here, I'll actually have to put in my details, the real details, true details over here because it does require my legal name over here. So I'm going to do that and then click Create. Now I've completed the payments profile, and I added a credit card, which was charged a very minimal amount for verification, and we're presented with this welcome screen. So a small disclaimer over here that please make sure that you read and understand all the things that you are, you know, entering and accepting as policies from Google, because this is a live account that can be used for, you know, hosting things that can be charged amounts, right? And you are responsible for the creation and conduct of this account. So do give that proper attention and consideration before proceeding, right? Now, over here, we ask some very basic stuff like what best describes your organization needs. So let me just say it's a very, you know, small company. I guess startup, right, and we click next. And what brought you to Google Cloud? Let's say learn more and Explore and then what are your interests? So let's choose web and mobile laps for now. And then what best describes your role and you can put in whatever suits you. I'm going to put Engineer developer over here and click Done. Okay. And now, as you see, you know, you have the welcome page and you have some free credits to use over here which expire in around three months of time. Okay, so let's check out the project that we have over here. So Google has already created a project for us, which is called the MIFirstPject, and it has a specific ID over here, and we'll stick with this for now and use this for further setup. 34. 8.3 Install and Setup Google Cloud Command Line Interface (gcloud CLI): All right. So let's move further. Now we'll install the GCloud CLI, which is the command line interface for Google Cloud. So let's search install the Google Cloud CLI. All right. And we get this link. Let's click here. Okay. And here we are with all the instructions. So I'm using MCOs and I'll choose this. So first, what we need to do is that we need to confirm whether we have a supported version of Python installed or not, right? And let's do that. So we'll open terminal, and here we have our terminal window. And then let's just follow the instructions from Google Spade. So we first need to check, you know, whether we have Python three or not. So let's just check Python three. We and we get we have Python 3.12 0.2 installed, right? And in case you don't have this installed, what we can do is that we can install a Python version by going to Python DelisF Macua. So let's look at that as well, once, right? So it says, you know, the latest one is Python 3.13 0.1. So let me just try to install that over 3.12. So when you scroll down, you see all these files available. Now, since I'm on MacOS, I can use this particular file over here just to confirm what MacOS version you are running, you can actually click on you can actually press Command Space and you can select about this MAC, right? So what I'm going to do is I'm going to click on this file. And allow the downloads, right? And I'm going to wait for this to download. Once you have downloaded this installer for Macaws, you can go to your downloads, click on this and open that particular package over here, and you'll be presented with the Python installer. So you can follow the instructions in the installer. I'm going to do that right now for myself. All right, so now I click on Install. Okay, so now this is going to install Python 3.13 0.1 for me. So for now, I'm going to click Close and I'll move the installer to the bin. And now let me go to the terminal. And if I just do this again, I'll get the updated Python version, which is Python 3.13 0.1. So this way, you can install Python if you don't already have it installed, and now we can continue with our Google Cloud command line interface setup. So let's go back to our browser and click on back to go back to Google Cloud. And let's go on to the next step. So the next step is to download one of the following, which is the package for Google Cloud CLI. All right. So what I'm going to do is I'm going to use the 64 Apple M one silicon because that's what my machine is. Let's click on this and it says we want to allow download. And again, we allow the download and wait for the download to complete. Okay, so once the download completes, let's go and select a downloaded TAR file and it should automatically expand all right. And now we see that, you know, we have downloaded the Google Cloud SDK. It's expanded into a folder over here. And what we're going to do is we're going to move this to our development directory that we had built last time. So we'll go to development. Over here, we press Command Enter to open a new terminal to open a new tab, and let's just try dragging it right over here and we have it dragged over here. So now, you know, all our stuff is well arranged inside the development directory. Okay, so now since we have the SDK downloaded, we can go on to the next steps, which is to actually install it. So let's copy this command from here to install the SDK and let's paste it in a shell. And of course, you know, we need to shift to the development directory and then paste this command. This is going to install the Google command line interface for us, Google Cloud command line interface. And do you want to help improve Google? Let me choose now for now over here. Okay, and, you know, it gives me a set of components that it has installed. Apart from the components, it'll also update your path variable and enable shell command completions, and it also asks for a RC file for any kind of settings that need to be put in in that file. So I leave this blank to use the default one. I don't want to run the Python Installer since I've already installed it, so I'll say no over there, then I go back and start with the init command. So this is the innit command for me, and let's just paste it over here. So this will ask us to actually log into our Google account, and there that is. So you must sign in to Continue. Would you like to sign in? So I'll say yes. So sign in using your account over here. Once you've signed in, it asks for permission, so I'm going to click Continue over here. Okay, and now it says you are authenticated with Google command line interface. So I'll go back to the terminal, and it says, you know, pick a Cloud project to use. So this is going to be the default project that it's going to use, and I'm going to use the first item so I'm going to press one and enter that. So it set the current project now, and it seems all the int aspects have been completed. 35. 8.4 Build Docker Image for Google Cloud: Guys. So now we are going to deploy our server to Googles Cloud using Cloud Run. To deploy our MCP server to Google's Cloud, we need to first build the Docker image for that for Google Cloud. Let's change to terminal server directory. All right, so I'm going to change to MCP servers terminal server SSE server directory. Then I'm going to use a Docker build command. I'll specify the platform as Linux slash AMD 64, which is needed for Google's Cloud. And I'm going to tag this as per Google's Cloud naming conventions, which is gcar dot IO for Google's Container Registry. Then we have the AI Language Pd, which is my project name, and then we have the name of the image and the dot for the build context. Let's press Enter. All right. So once the build is done, we can actually push the image to Google's container registry from where we will be able to actually deploy it to Google Cloud. 36. 8.5 Deploy MCP SSE Server to Google Cloud Run: All right. So once the build is done, we can actually push the image to Google's container registry from where we'll be able to actually deploy it to Google Cloud Run. To push the image, we are going to use docker pushgc dot I, slash the AI language prod, slash the MCPSSE server, and this is going to push the image that we just created. All right. So once the push command is completed, we'll actually run the Deploy command. This is GCloud run Deploy. We provide the name, which is MCP SSE server, then we provide the image tag. We basically use the managed platform, we choose a region and we provide a port, and we allow unauthenticated access for this demo. Be sure that you actually deactivate the Cloud run API after you have tested it yourself and use some kind of security mechanism on this as leaving it unauthenticated might be risky. Let's press Enter to deploy it. All right. So this deploys and provides us a URL for the service 37. 8.6 Test MCP SSE Server on Google Cloud: Now let's clear this and move to our client directory. Now we'll write UV run and then we'll write the name of our client and we'll provide the URL that we just got, and we'll put SSE as the endpoint because that's needed for initialization. Now, let's press Enter. And, guys, is this not amazing that now we have our MCP server running on Google's Cloud over here, and we're able to run our client with that particular endpoint. So now we get initialized SR client listing tools and disconnected to server with tools Run Command and add numbers, MCP client has been started type quid to exit. So let's type our query. So we're going to use the AdnumbersTol, and I'm going to ask it to add to numbers. Now, I've asked you to add two and four using the add numbers tool. Since it's an easy operation, I specifically mentioned the tool to be used because I want Gemini to use the tool rather than just adding numbers itself. And now we'll check whether our MCP server hosted on the Cloud can actually connect with the client that's running on our laptop right now. Let's press Enter and see what happens. Okay, so Gemini requested Tool call add numbers with arguments four and two. That's perfect. And then the sum of two and four is six. And, guys, is this not completely amazing that we have been able to build our MCP server, host it on the Cloud on Google Cloud, and then basically run this using a client on our laptop. And this is the first step towards basically making MCP servers on the web and make them easily accessible to clients all over. 38. SECTION 9 START - STREAMABLE HTTP MCP SERVER - 9.1 Quick MCP Recap and What is Streamable HTTP: Today, we look at the transport mechanism in model context protocol, which is called streamable STTP. It's a new mechanism compared to the two earlier ones that we had, which were STD IO, it's still there, and then server sent events, which is now possibly going to be deprecated. I'll go over the client to server interactions possible over the life cycle of one session. So you can head over to model context protocol dot IO slash Introduction and they give a pretty good introduction about MCP. I'll just run through a very few basic concepts over here and as you might already know that it is a communication standard released by anthropic and it's designed to facilitate structured interactions between clients, which we call as MCP clients and MCP servers, which you can see over here. These are a bunch of servers over here which are connecting to a host with the MCP client. And this client is, for example, application on your computer or mobile device that requests data or actions. And can access other resources as well. So the clients typically host or access an LLM, like Cloud or GPT or Gemini or whatever. This can be an LLM based agent, and that can then use MCT. So the agent can use Model Context protocol and have access to all these servers and tools on the servers. So the agent can decide that it wants to use a tool exposed by one of these servers and then use that to access, let's say, a datasource A or a datasource B through a different server or access resources over the Internet or remote services like remote service C mentioned over here. Through a web API through this MCP server. But the communication that happens between the host with the MCP client and the MCP server is through the model Context protocol. The server basically processes the client requests and sends back responses or it can send back streams of messages through server sent events, which we look at and even notifications. So it's a bidirectional client server communication architecture as you can see over here. Now, since there is this communication happening, we need to define a standard transport mechanism for this client server communication and soci does that and they give us two of them. So one of these transport mechanisms is streamable SGDP and the other one is STD IO. Streamable SUDP enables communication over the Internet. So this server does not need to live locally. It can be hosted on some cloud platform, and streamable SDDP will help your client that might be running locally on your computer or you might be accessing it through a website which is hosted on some other server. So it can communicate to this external MCP server, which is a remote server through streamable SDDP. Transport mode. So this enables the communication over the Internet and the servers can handle multiple clients simultaneously through continuous message streams. So that's the advantage of SEDP communicate over the Internet and handle multiple continuous message streams. With multiple clients. So what is SDD IO? SDD IO is one more transport mechanism and it is a client server communication, which on the other hand enables communication through standard input output channels. You might have a MCP server B. Let's say that's running on a local subprocess on your computer and the client server communication can happen locally. So you can enable that using SDD IO and this basically uses the standard input and output for communicating to and from the client. 39. 9.2 Overview of Streamable HTTP using Sequence Diagram: So what are we going to do today? We are going to explore MCV communication over the Internet through streamable GDP and we'll break down each step and we'll show this in a sequence diagram. So let me head over to that sequence diagram now. Great. So now let's see this sequence diagram. This is a diagram that shows the two participants, the client and the server in this transport and the interactions between them over this entire life cycle. So as we go down, we see the lifecycle events like initialization, client request, and so on. And these are the two participants that are interacting, and these are the granular interactions that are happening between them, which are shown by Aosovos. This is basically what is a sequence diagram. Client will initiate communication by sending requests and notifications. The server will respond to client requests, send back data, manage ongoing communication, and might also initiate requests for additional data. Streamable SEDP is what allows this continuous communication through three mechanisms. There are SEDP post requests. There can be a post request made by the client to the server. There are also get requests that can be made to initiate this communication and allow the communication to happen. There are server send event streams so the server might send back streams of data. You might see the mention of JSN RPC at different places or Jason messages being sent. So JCN RPC is the protocol for messages. So the messages being sent are JCN RPC messages encoded in UTF eight, and JCN RPC is basically a lightweight text baase format for exchanging data and relies on JCN which is JavaScript Object notation, then UTF eight is an encoding standard capable of encoding all possible Unicode characters. So that ensures that messages sent across the network are universally understood regardless of language or symbol complexity, et cetera. So that is the protocol for messages that is being used inside of streamable SGDP. So we'll look at five different aspects of the streamable SGDP communication life cycle. So one is initialization, which is shown here in the gray box. So the client does the initialization. Then in the green box, you can see client making requests to the servers and how is that handled? Then in the yellow box, you can see client notifications and responses. So how does the client send notifications or responses to the server? Then the purple box over here, we have the fourth one, which is listening for messages from the server. The client can actually listen to messages being emitted from the server. And finally, we have session handling. So how are different aspects of the session handled in stream let? 40. 9.3 Initialisation Phase: Let's start with initialization. The client sends to the server a post request on the slash MCP endpoint, which is a initialized request to start the MCP session. It specifies the accepted responses, which is application JSON for a single simple response in Jason from the server. And the other one that it specifies is text slash event stream, which is basically a stream of SSE messages that it can receive. As per the streamable SVB protocol, the clients must accept both of these. The client cannot say that we don't accept SSE messages as a stream. We only accept simple JSON responses, but that can't happen. Client if you build a client, you have to build for both of these. Secondly, this initialization request does not specify any MCP session ID. So this MCP session ID will be generated by the server. It is an optional ID, but in this full sequence diagram, we assume that the server does create that MCP session ID because that then enables management of the session, right? And then there's the initialized request that is included as part as a part of this post request. The server will respond with an initialized response. It provides a unique session ID, which is MCP session ID, and this is what we call an initialized response. This session ID will be used for subsequent communications, and if the server responds with the session ID, the clients need to include this MCP session ID in the header for all further requests, and that is a mandate from the protocol. After this initialized response, the client sends a post request on the MCP endpoint with a initialized notification indicating it is ready for further interactions. I'll send the MCP session ID and the notification in the body, and the server will respond with a confirmation that it's received the notification with an SDDP 202 accepted response. That is what happens during initialization. 41. 9.4 Client Requests Phase of Streamable HTTP: Now we go on to client requests. What happens over here is that the client, which is represented by this vertical line sends a post request on the slash MCP endpoint containing the session ID, and again, with the accept header, which says it accepts both kinds of responses and a body with the request. Whatever the request is whether I want to run this tool or whatever that might be, the server can respond and it has two pathwayse. There's one option, which is a single response. And the server immediately sends a single JSON object response and the response is in the body and that just basically completes the response. The second option is that the server can open an SSE stream. So the server either responds with content type application JSON or with a text slash event stream content type, which basically means that it is initiating an SSE stream, continuously sending data and interacting with the client in real time, where the server sends to the client continuously SSE messages which are real time updates. So these are the SSE messages from the server. And there's an optional request for input that the server can send and then the client can respond. It can send the required input back. There's also an optional notification. Jason RPC notifications that can be sent by the server to notify the client about whatever might be the important aspects that it wants to. And once all this is done, the server can close the SSE stream with a final response over here. So this is how the communication happens when the client raises a request, 42. 9.5 MCP Client Notifications and Responses: Next we have client notifications or responses. What happens over here is that the client sends notification or responses via post slash MCP to the server and the server responds in two ways. Either it sends the 202 accepted with no body. I just accepts the notification or response or it can respond with a 400 bad request, which indicates that some invalid input with error has been provided and it'll send back an optional JCN RPC error response as well with this. So the server either accepts this notification or response or the server cannot accept it. 43. 9.6 Client Listening to Messages from the Server in Streamable HTTP: Next is the client listening to messages from the server. The client can send a get request to MCP endpoint and request to open an SSE stream explicitly. I'll say it accepts texts event stream with MCP session ID with a G request. And what this means is now that the server can respond by saying that SSE is supported and it can open an SSE stream, or the server itself might not support SSE. SSE the server has an option to not support SSE, so it can say SSE is not supported. This is a trivial case where it says that 405 method not allowed, and that is the response that the client gets back. But the non trivial case is where it actually opens the SSE stream, and then something similar happens to what we have seen when clients initialize requests. So the server responds by sending SSE messages in a continuous stream. Or optionally, it can also request for inputs and the client responds with a response, or it can send some kind of a JCN RPC notification if needed. So these are optional, and if it accepts SSE stream, it can send messages over the SSE connection. 44. 9.7 Session handling in Streamable HTTP: Finally we have session handling and how is this done in streamable STP? So the first part is resuming after disconnect. So the client can resume a connection after getting disconnected by sending a get request to the MCP endpoint with the last event ID. And this is an event ID that the server might have provided in one of the last messages that it sent. And then the server can take in this request and then resume from the last event, so it can replay all the messages, post event ID so that the client can get that information. So the server also has an option to end the session if it wants to for whatever reason, right? And in that case, if a client sends a request with a session ID that the server has closed down, then the server must respond with a SCDP four or four not found response, and the client in turn has to understand that this session is closed or it might be invalid or expired, and it has to start a new session with the initialization request that we saw in the beginning. So this happens when a request is made from the client with a session ID that is either closed or invalid or expired. And finally, you have the client requesting to end the session. The client can send a delete MCP request with the session ID. So the server has two options. It can either allow that session termination, and this is the allowed case over here, and the server in this case just sends a 204 response with no content saying that the session is successfully terminated. The server might instead also say that the clients cannot end session like this and this is something that the server does not allow for example. In that case, it can send a 405 method not allowed, and session termination is not permitted, which is what is communicated to the client. 45. 9.8 External Resource for keeping up to date: According to me, are the major interactions that happen between the client and the server in streamable SGDP when it's used as a transport mode for MCP client server communication. This covers most of the interactions that happen. There are a few that might not have been covered and you can actually look at this particular website, model Context protocol dot I to do that, you can actually go to the menu over here, and then you can scroll down to protocol and go to transport. And once you click on transports, you have all the details about how SGDIO works, how streamable SGDP works. And there's a lot of textual detail. I've tried to convert this into a diagram with most of these things. But just as a caveat, you should also read through this and one of the rules is that whenever you work with some kind of protocol, you understand the ins and outs of this is something that is updated with every version of MCP which might not be possible 200% in the video. So whenever you see this video, please go to the latest version over here, go to the protocol and understand the transports from here to see if something has changed or something has been updated or missed so that you are abreast with all the latest updates to this protocol. MCP is pretty new, you expect updates to happen very, very fast as well. You can see that with streamable STDP which is now going to be the recommended transport mechanism in place of the earlier SSE one. This is the sequence diagram that they have. It has lesser number of interactions mentioned over here, which just simplifies the sequence diagram, I guess, but it leaves out a few of the interactions that we might have covered in the other sequence i. Keep this page handy and go through this to look at the latest updates and for anything that I might have missed or maybe presented incorrectly as this protocol is very, very new and you expect this to change very, very fast. 46. SECTION 10 START - Streamlit User Interface for MCP Client - 10.1 Streamlit UI MCP Client Overview: So today we are going to do something pretty amazing. We're actually going to add a user interface, as you can see over here to our Python based MCP client that actually works with MCP servers. We're going to do this with Streamlt and you can see that UI on my screen right now. So before we begin, let's have a look at the user interface and what we are going to build in this particular video. So this is how the overall user interface looks. There's a main area for the chat and a side bar over here. This is basically the user interface for our MCP client. The client is built using LangrapsRact agent and uses Gemini's API as the large language model, and it's written in Python. The UI is built using Streamlt and this basically is the entire client. Let me zoom in to show you the different components of this particular client. We can collapse the sidebar from here, and you have the title over here with the logo. And you have a subtitle where I've just put a subscribe link to a YouTube channel. There's a section where the chat comes in and you can see the messages sent by the user and the response from the MCP client. Then there's a chat box to put your query and you can press Enter to simply submit your query for processing, or you can press the Send button. You also have a new conversation button to start a new conversation, and you can save the conversation by clicking on Safe conversation over here. You can expand the sidebar by clicking this button, and then you have some settings over. So you can select what kind of MCP client do you want? So you can either have MCD client that actually connects to SDD IO servers, which are basically Python and JavaScript scripts that run locally on your computer, or you can use an MCP client that can connect to a server over the web or the XDDB protocol, which uses server sent events as the transport protocol. I have included the code for both of them, but the SSE code is not fully implemented yet. You can actually use it as a placeholder or a starting point if you'd like to. When we select the SCD IO server, you can actually upload a conflict dot JCNFle with all the MCP servers over here, and you can click on Browse files to do that. Otherwise, the system uses a default confit file, which is the AI language underscoecfict dot JSON. You can see the historical conversations that you have saved over here. These are saved in a conversation folder with the timestamp at the end of the file. There's also an expandable log output block over here where you can actually see the entire log for your MCP client and server interaction. All right, so let's preview how this works now. 47. 10.2 Streamlit UI Demo: So let's preview how this works now. So we press New conversation to start a new conversation. So let's first type Hi and press Enter. Now, you can see that it's basically running it in the background and we get the response from MCP. Hi there. How can I help you today? So I'm using user to tag the messages from the user and MCP to tag the response messages from the MCP client and server. All right. So now let's write a query. Create a file streamltUnderscore success dot TXT with the text Streamlt success using the Run command tool and press Enter and see what happens. Again, it runs the query. Okay, and we get the response that I've created this file Streamlt Underscoe success dot tXT with the text streamlt success. So let's check this out in the Finder Window. All right, so this is the Finder window with the workspace for our terminal server, and we see that we have a file called streamltUndersco success dot TXT right over here. Let me open this file now. Okay, and you can see that it has the text streamlt success inside the file. This means that our client and server are working well together with the UI. All right. So you can also basically click on Save conversation over here, and this is basically going to save the conversation. You can click on new conversation by clicking this button over here, and this is going to start a new conversation over here. Now, when you actually click on this sidebar over here, you have the option to load conversation. So let me just load this particular conversation. And this is the latest conversation that we just saved, and you can see that you have the entire message history over here. Now for the MCP client Config JCNFle, you have the default file, the AI Language underscoconfg dot JCN, which is basically in the same directory as the application. In case you want to provide your own file, you can click on Browse files over here. You can choose a file and it'll basically replace the content in this AI Language underscoconfit dot JcN file, and then your client is basically going to use that file. You also have an option to change to a different kind of MCP client and server combination, which is SSE. So SSE stands for server sent events. It's a transport method that is used by MCP clients to work over STTP. I have provided some placeholder code for this, but this is currently not active in this particular client implementation. You can have a look at that code and modify it for your needs if you need to. I've just worked with the SDDIO client over here. 48. 10.3 Comparing our UI with Claude Desktop!: Is basically to show how you can actually build an MCP client, and this is the first step to build an app of a magnitude like, let's say Cloud desktop, which is also an MCP client, one would need to actually include a lot of features to have a wonderful user experience. But this is just meant as an educational code to show you how you can use streamlt to build a basic client UI for your MCP clients and servers. 49. 10.4 Setup Directories (skip if done earlier): Once you have UV installed, you can actually set up your MCP directory structure. So what I do is that I actually set up an MCP directory in my home folder, and then I set up three directories over here, clients servers and workspace. In the clients directory, I save all my clients, and I'm going to save the Langhain MCB client over here. In the servers directory, I have saved all my servers, all the prebuilt ones that I have downloaded, and all the servers that I made on my own. Then I have a workspace folder over here because if I want the MCP servers to take any actions locally on my computer, I use the workspace folder for any kind of file creation, deletion, et cetera. For now, we're going to head over to clients folder and you see that I already have an MCP client over here. You can actually use the Github repository link to check out this MCP client folder, once you have checked this out, you can actually go inside the folder 50. 10.5 Setup Google Gemini API Key (verify again if done earlier): Before we do that, we need the Gemini API key. So I'm going to head over to Chrome, and I'm going to go to atudiogogle.com. When you reach this site, just click on Get APIKey. You, of course, have to be logged in using your Gmail ID. You can click Create APIKey to create a key. I already have a key created over here and I can just click this button and copy the key. Do make sure that your API keys are secure. You should not share them or embed them anywhere in the code or in any repository. I'm going to disable this APIKey after I finished recording this video, so I'm going to just let it remain visible over here. Once you have copied this APIKey head back to the terminal and create an environment variables file by typing touch dot NV and press Enter, I already have this file over here, so I'm going to just open this using NNO and as you see, I have defined APIkysGemini APIKey and Google APIKe and I have pasted my key over here. You can actually write this line over here and paste your key next to it. I have used two environment variables, Google APIkey and Gemini APIKey because in my personal project, I like to use the environment variable Gemini API key. However, an chin expects the key to be present under an environment variable called Google APIK. Just to avoid any confusion and allow both of the variables to be used, I actually defined the key twice using two environment variable names. You can do the same. For Lang chain, you need to use Google API press Control X and save the file before exiting it. Now you have your environment file set. 51. 10.6 Create Virtual Environment and Install Dependencies: We can create a virtual environment which basically helps us keep our project dependencies separate from all other work that we're doing on a computer. So you can type U V, NV and press Enter to actually create that environment. I already have created that, and if you're following along from my previous videos, you would also have this directory and environment created, so you don't need to create it. For everyone watching new, please create this environment. Once you have this environment created, you can actually activate it by typing source dot nvlashBN slash Activate. And this basically makes you enter the MCP client, virtual environment. Okay, so now we are going to add some packages that we need to develop our MCP client. These packages are Lang chin, the Lang chin MCP adapters, Lang Graph, Lang chin Google Gen AI package, Google Genitive AI package, and the Python dot Environment package for the environment variables. After writing UV ad and the list of packages, press Enter, and I already have this installed, but it will take a few seconds or a few minutes to get this installed. All right. So once you've added all these packages, you need to add the other packages for specifically streamed it and the UI that we are building. So we're going to add the streamlt package from the file. We're also going to add Nest underscore AC IO and we're going to install Pillow as well. So these are three additional packages that we want to install. All right, so just type UV add Streaml Nest underscore ASN, IO and Pillow, and this is going to install these three packages as well. Alright, so this installs all the dependencies for your client. 52. 10.7 Get Streamlit UI Code: All right. So to get the code for the UI, the client, and the server, you can actually refer to the links in the description. You'll see that right now we are referring to the MCP client folder where we have all the clients that we have previously implemented if you have followed through the previous videos. Over here we have three different files of interest. One is the streamlint client UI dot PY file. This implements the entire streamlint UI, and this connects to the different client implementations above this file over here. So we have two client implementations for now. One is the SDD IO client implementation. Again, this is basically all the servers that you can actually specify in your conflict file, and these run locally on your computer. You also have SC dot PI implementation, which is right now just a placeholder for you to use and implement further if you actually want to work with this. For now, I'll be covering the UI file and the SDD IO server file. 53. 10.8 Streamlit App Imports and State Initialisation: Let's go through the streamlt client ui dot py file code work through and setup together. So to begin with, we have the imports and I've added very detailed instructions throughout the code for you to help understand what each line means and also the install instructions. So Streamlt is the code library that we use to build the UI and we import it over here. Then we have ASN Kio for ASN processes, especially for the tool communication and we import it over there. We have OS which basically provides file system interactions, and we have JCN to read and write the conversation data to JCNFles. We then have datetime which is used for timestamping, we have Nest Async IO, which you can actually install by typing PIP install Nest Async IO. This basically allows nested use of Async IO event loops, and this is useful in interactive notebooks or streamlt. Then you have the Python image library, and this is used to basically style the images like the logo in our tool and you can install it by typing PIP install Pi. Have the estimL components for basically more advanced customization and this basically completes all our inputs. Then you have nest underscore asynco dot apply, and basically in Python, when you use something called Async or await, you're telling the program that do this task in the background while waiting for other things to finish. But Python normally only allows one event loop at a time. Streamlt and Jupiter, all tools like them already use an event loop in the background. So if your code tries to create or run a new one, Python throws an error. So this line is saying that it's okay, let this new event loop run inside the existing one. It's like nesting one loop inside the other. So this basically patches Python's Async IO, you can safely run nested event loops, especially useful in interacting environments like the client that we are building with streamlt or things like Jupiter notebooks or even repels that have already running loop inside. Now you have the app session state initialization. We have a conversation list. If that's not already present at the session state, we initialize that with an empty list. We have a client config, and again, we initialize that as SDD IO, which is the type of the client. This is extendable to different client types. You can basically include categorized clients over here. You have a server URL for SSE type of clients and you have a SDD IO config file for the SDD IO type of clients. Then you have a placeholder for a reusable client object. So if client instance is not in the session state, we basically assign it to none, and we'll basically initialize this later on. There's a theme for toggling dark mode. I was trying to include this in the code, but I ended up not including it. But if you had to, you would store that in the session state. Then you have the logs which we saw in the log blog and we initialize that to an empty list. All right. Then we have a submit triggered flag in the state, and this is just to identify that if somebody is submitting the query in the chat box by pressing the ent key rather than clicking the Send button. Then there's a flag to prevent infinite reruns of the loops after processing a query, it's a query executed flag, which is initially false and that's what we set it to. We'll use it later on. And there's a pending query string to actually hold the current query to be executed after submission. Again, we'll look at the usage of these state variables as we go along. 54. 10.9 Code for Utility Functions: We have some utility functions and the first one is run async in event loop. So this function is like a task manager for background jobs or also known as routines. Normally to run an Async task in Python, you need something called an event loop, and it's like an engine that handles multitasking, but streamit already runs its own engine. So if we try to run our own separately, Python gets confused. What this function does is that it checks, is there already an event loop running? If no, it basically creates one. And if yes, it politely asks the running loop to add our task to its schedule and waits for the result. Then we have the add log message. So it's a logging utility that logs the messages with a timestamp to both console and UI logs. So this function is like a note taker or diary. So every time something happens like receiving a message or processing a query, this function writes it down. So it adds a timestamp, so we know when it happened, it adds the message to both the screen, which is in basically the streamed state and the console which is basically printing it on the console. This basically will help you in debugging flagging events, or just seeing what happened when. 55. 10.10 Streamlit App Sidebar Code: So then we have the sidebar for the settings and the log view. So this line with st dot sidebar, this creates a sidebar panel on the left side of the streamlt app, and everything inside this block gets displayed in that sidebar. It's like saying that, whatever you're adding over here is basically stuff added to the left hand menu. All right. So sd header settings adds a section header labeled settings at the top of the sidebar. So this basically shows a radio button that lets users select between SDD IO and SSE. The selected option is stored in the session state under the client config as client type, so it can be used later. And we use Adog to basically log this selection which shows up in both the terminal and the UI. All right. So then we have the SDDiocfig dot Json or the fallback to the default option if we don't provide a file, so what we do is we basically upload our Cfict dot JCN for SDD IO using a file uploader. So this basically adds a file upload option where the user can upload at JCNFle. The JCNFle is expected to have the confit for the MCP servers, and this is used later to connect to the Bend tools. So if a file is uploaded, we save it to disk with the name the AI language underscore config dot JCN. This apps the standard config file your Bend code expects. So if the file is uploaded, we basically store it on this path, which is in our, you know, directory over here. And we'll actually open this file and save it. Then we'll set the client SDI on Square Config with this path, and we'll also print a success message and analog and add this to the log. If a file is not uploaded, we'll basically use the default file, the AI language underscconfg dot JSON. And just after a basic check if that path actually exists, which it should because we already have the file over here. We basically again set it to SDDI or config in the session state, and we add a log statement around that. If just in case this file is not present, you know, we'll actually provide a warning for that and again add that warning to the log. All right. So then we have a section on loading the conversation. This is basically a horizontal divider, and then we have a header with the title load conversation. So we then set up our conversations folder or directory, and we actually make that if it already exists, that's okay because this prevents any kind of errors because of that. Then we list all the files from the conversation folder. And if we do find any conversation files, we basically go through each of these files and we get a file path. Then we open the file in read mode and we load the Json from the file. We load a review from the first 20 characters in case you want to show it. And then we add a button to load this particular file name. If the user clicks this load button, the conversation is stored into memory, and sessionstg dot conversation is set with that value, and then a success message is basically shown on the UI, and it's also added to the log. And if no old chats were found, we basically then, you know, provide information that we don't have any saved conversations at this time. We finally have, again, a section divider, and then we have a logs viewer, and this is basically a text area with all the logs from our session state logs. 56. 10.11 Building the Main Chat UI for the App: So next we have the main chat UI, and on the top of the chat, we first render the logo and the title. So call one and call two basically splits the top of the app into two columns, and column one is basically one by seventh of the total width, and column two is basically six by seventh of the total width. And this is basically used for the title, and this is used for the logo. All right. So for column one, we will load the image that's present at assetlashogo dot JPG, and you can go and see that we have an Assets folder over here with the logo dot JPG file over here. Then we take the smallest dimension height or width to make a square crop and this will basically help us make the logo circular. This creates a circular mask, a white circle on background that will apply to the image to make it look round. Now, this crops the original logo into a square and applies the circle mask as Alpha or transparency. Anything outside the circle basically becomes transparent. This then finally displays the circular logo in the first column using full width of its container, and that's how you see the circular logo on the top. All right, so then you have the second column, and over there, we basically show our apps main heading in the right column. Okay, so for a subtitle, I use a YouTube call to action as a clickable link, and this is basically what we do over here. The unsafe allow STML equal to true basically allows us to use basic SML formatting like bold text, and the markdown formatting is basically used to style the link. Then we show the past conversation. So basically loop through all the previous chat messages stored in memory. We get the timestamp, we get the sender, and we get the message. And then we display it in bold using markdown format using this particular line and in this particular format. Then we have a callback function that sets the submit triggered flag when Enter is pressed. So this function is called automatically when the user presses enter in the box. So we first check if the input isn't empty. So if it's not empty, we set the submit triggered flag equal to true to indicate that a query needs to be processed. This just means that, and then we copy the text to the pending query, so we can use it after streamlt loads the app again. On it. So then we have the input box. So this basically renders a single line text input. The label is your query. When the users presses Enter, submit on Enter is automatically called, and the input is basically stored in query underscore input inside the session state. The placeholder text that we use is type your query here, and this is that input box. Then we have three action buttons for sending the query new conversation button and a save conversation button. So the Send button basically submits the query to the MCP agent the new conversation button clears the chat history and starts afresh. The save conversation button saves the current chat log as a Todd Jason file. 57. 10.12 Core Logic For Query Handling: So now we have the code logic for query handling, and first, we have this function. So this is an ASN function that sends the user query to the back end via SDD IO and returns the response as a string. We add a log entry that we using SDD IO mode. Then we attempt to import the run agent function from streamlt client SDD IO. This is the implementation that we have over here, and we'll go through this later on. And we handle any kind of import error if it happens over here, and then we basically run the agent with the query that we import it over here and the query that we received over here, and we get the result, we add a log saying that we have processed the query and we return the result. So then we have the handle query function and this function basically handles the full lifecycle of a single message. The user sends it, we send it to the back end and then we display the response. So if the user types quid, we set the conversation to an empty list over here and we log the same. Otherwise, we get the current time to timestamp the user message. We save the user query in the conversation history and we log it over here. Then we send the query to the back end using the function that we just looked at and we wait for the response and we are using the SDD IO client over here. We save MCPs response over here. This is the assistance message basically and we log that two over here. Then we set query executed equal to two so that we don't keep on re running this query on each reload and this basically helps us prevent infinite loops for running the query. 58. 10.13 Trigger Logic for Send and Other Chat Buttons: We have the main trigger logic. So if the user has clicked on the Send button or the user pressed Enter in the input box and the query hasn't already been executed in this cycle, that is the query executed flag is false, we grab the query from the pending query in session state, and if the query exists, we basically run the life cycle for the query using handle query, which we just looked at using this helper that we looked at in the beginning, which runs async code inside stream. And then we reset this flag to false so that the next keystroke doesn't reiterate. Then we re run streamlt app after query completes to refresh the UI. If the query executed is equal to true, we will reset it to false so that we can basically set up for the new query and we force a UI rerun usingst dot rerun to refresh the screen and show the new chat messages. Then we have the new conversation button logic. Basically clicking this clears the entire chat history and logs it and then it reruns the app to reflect the empty state. Then we have the save conversation button. This is basically going to help us save the chat to a file we basically make sure that the conversations directory exists over here. Then we cream a timestamped file name using this particular statement, and then we provide a path with the conversation directory and the file name joined together. We open that file and then we basically use Jasen ton dump to dump the conversation over there. We then basically add a log regarding our successful save, and we also show it on the UI. This is our entire streamltUnderscore client underscore UI dot PY file. 59. 10.14 Streamlit App MCP Client Code: So now let's look at the streamt client stdio dot PY file that we're actually using to run the agent inside the MCP client. This is basically the Lang chain MCP client with config agent. So if you've already looked at that particular lecture or video, you can actually skip this explanation. Otherwise, we're just going to quickly walk through the concepts over here. All right. So this file basically implements a lang chain or Lang graph based MCP client. It loads the config from a JCN file which is specified by the AI language config variable environment variable. And if you don't find this, it basically falls back to the local file over here. It connects to all the MCP servers that are defined in the config, loads the available MCP tools from each connected server, and it uses the Google Gemini API via Langraph and anchin to create a react agent with access to all the tools. Then it runs an interactive chat loop, so you can actually independently run this file as well. But we are going to use it with our client UI. All right. So then we have the regular imports that we have looked at earlier when we have been designing our clients. So we have these imports for Async operations, environment variables, et cetera. We have the MCP client related imports for managing the MCP client session and server and for establishing a STD IO connection. Then we have the agent and large language model imports. So we have an adapter to convert the MCP tools to Lang chin format. We have the react agent that is pre built and comes with Lang graph, and then we have the Google generative AI zapper for the Gemini API. Then we set up our environment, so we basically load the dot ENV file, which is our environment. You can actually see over here that we have the dot ENV file over here, which is this, and you have a Google and Gemini API key defined over here, which is the same key. We just use two different variables to, you know, handle both options in our code. Then we have a custom encoder, which basically, you know, manages the formatting of our JCN content by checking for a content attribute inside the JCN keys. Then we have the read configuration function. So this basically reads the MCP configuration JSON so we actually have the AI language conflict environment variable. If that is set, we use that conflict path. If that's not set, we basically check the current directory and we formulate the conflict path based on the current directory name over here and the AI language conflict dot JCNFlem. So this basically gives us this file path. Then we open whichever file, we have selected over here, we open that and we load the JCN. We of course do some exception handling over here to handle any kind of errors. All right. So then we have the run agent function and this basically takes in the query as a string and returns a string output for the UI for our MCP client. This is very similar to what we have done over here in lang chain MCP client with confect or PI. The only difference is that the query is a input over here that comes from the UI rather than coming from the function over here itself as a query input as a user input from the terminal. So basically this connects to all the MCP servers defined in the conflict file, loads their tools, and then processes this query. Now, this is the Google Gemini LLM instantiation. We have used this to specify the model over here. We also use the API key that we are basically getting from the environment variables, and we then set up some other parameters which we have explained over here in the comments. Then we read the conflict file and we get the MCP servers list from the conflict file by using the MCP servers key in the config Jason. If there are no MCP servers, we just print that we could not find any MCP servers. Otherwise, we create an empty list of tools, and this is basically in the end, going to be used to pass to Gemini. Or the react agent that we are using through that, it'll basically go to the Gemini APA so that the late language model understands what tools it has available to use. All right. So we use an Async exit stack to basically manage multiple async resources, and then we iterate over each server name and server info in the cp servers dot items. Let's just quickly look at our AI language confit dot JCNFle and you can see that inside MCP servers, we have two servers, terminal server and fetch. Terminal server is basically the name of one server and fetch is the name of the other server. And everything else is the server info, which basically is the command and the arguments. Now, going back, so we now understand we have the server names and the server info in all the MCP server items. Then we basically take one server at a time, we connect to it. We then get the server parameters using the command and the arguments. We use the server parameters to establish an STD connection to the server, and we get the read and write streams for that connection. Then we use these read and write streams from the connection and we basically create a client session that we store in session. Then we initialize the session, it basically is a handshake or setup operation that happens using MCP, we then use Lang chain's MCB adapter to load the MCP tools from the session, and we save it in the list of server tools. Now, for each tool in the server tools, we basically inform the user by printing that we have loaded this particular tool and we append it to the list of tools that we have declared above. We then do a final print over here and catch any exception over here, and this is basically done for each server name. In case there were no tools found, we basically do an appropriate print statement over here. We finally create a react agent using the large language model instantiation that we did above and the list of tools that we have basically got from the conflict json file after initializing all the servers. This is our agent, and then we take the query and we invoke the agent with that particular query. We get a response over here and we then print that response. We print that response after formatting it, so we basically check for messages in the response dictionary. And if we do find messages, we take them in reverse order. We want the last message from the AI, and if it has the content parameter, we basically turn that content. Otherwise, we basically return that no AI response was found in the message. Finally, we have the main entry point for this function defined over here. All right. This completes the client SDD PY file. We finally can look at the AI language conflict dot Json file over here. 60. 10.15 theailanguage_config.json and other files: Let's look at the AI language underscore conflict dot JCNFle. Over here, we've already had a brief look at it, and, you know, you have MCP servers key which has a list of MCP servers defined in JCNFmat and we have two servers over here. We have the FET server. This is a pre built server that I got from the Github for model context protocols prebuilt servers that I found online, and then we have the terminal server. So this is a server that we had created in one of our previous videos, and this is basically used to run commands on the terminal. So that is why we call it terminal Underscoe server and hence the name. And we use both these servers just to demonstrate that multiple servers can be connected to, and we can actually load all the tools from these servers and then use them with our MCP client. So before I move on to running this file and setting it up on the terminal, I actually also show you the conversation file so you can actually see that you have a conversations folder over here with two conversations. So let's open one of them, and this is how we actually save conversations. So it's a list of messages with a sender, which is the user or MCP. Then we have the message, which is high, and in this case, it's a response to this message which is hi, how can I help you today? And then we have a timestamp over here. At the end, also remember that we are using a logo, you need to provide a logo dot JPG file over here, which is actually going to be loaded onto the client UI and shown over there. 61. 10.16 Running the Streamlit UI: Run the UI type stream run Streamlt Underscore client UI dot PI. This is basically going to launch the UI for us. 62. SECTION 11 START - A2A or Agent to Agent Protocol - Lifecycle - 11.1 Introduction: Hi, everyone. Today we are going to take an exciting look at ATA protocol or agent to agent protocol, and how it works with two powerful tools model context protocol and agent development kit. We'll cover what ATA is, why we need it, and how it enables powerful agent collaboration across organizational or technological boundaries. We'll also look at the key components in ATA, which you can see on your screen right now and how are the typical flows managed in away like discovery processing and other flows that happen in A to a communication. So if you're a programmer or builder or even just technically curious, you are in the right place. All right. So let's start right at the beginning from a blank slate. To understand A to A, we need to first understand the concept of agents and how they work in the world of large language models or LLMs. We first have a large language model, and LLM is basically the abbreviation for it. So this is like GPT or Gemini, and these are trained on massive datasets that can generate natural language responses, write code, summarize documents, and reason across many domains. But by default, this large language model is stateless and passive. It waits for a prompt and gives a reply, and that's it. To do more, we wrap it inside something smarter. That's what we call an agent. Now, to do that, we have an agent framework, which is a software layer that gives this large language model memory, goals, and tools. So basically, it helps us build systems where an LLM knows what it's trying to do. It can reason step by step and call tools like APIs, search engines, or databases. Think of it like turning a simple chat bot into a helpful co worker with a brain, a to do list, and access to software. Now comes multiple local agents. So inside a single app or organization, we might have multiple agents. So these three can be multiple agents, one for writing one for analysis and one for database queries, et cetera. They can collaborate together internally using a shared memory, common context, or message passing. And then these together basically form our agent, which basically consists of multiple local agents collaborating together and which is basically called multi agent colab. Now, these agents can actually access tools, resources, and other kinds of APIs and enterprise applications through something that we called model Context protocol. And we've already gone through all the details about how MCP works. And MCP basically helps these agents use these APIs and enterprise applications through tools or other resources. 63. 11.2 Why A2A Protocol - A2A vs MCP: Here's the catch. Most agent systems are bounded by their own infrastructure. An agent inside one company or one cloud server cannot easily talk to another agent built elsewhere, say in another company, another data center or another programming language. This is what we call organizational or technological boundaries. Maybe due to API security, network isolation, or system compatibility, these agents cannot communicate past this boundary. What happens when agents need to collaborate across these boundaries? This is where things break down. Two intelligent agents, even if they are both brilliant can't help each other because there's no common protocol or language for them to communicate. And here is where agent to agent protocol comes into the picture. ATA stands for agent to agent protocol. It's a protocol that lets agent talk to each other across these organizational or technical boundaries. It provides a secure and structured way for agents to discover each other, send messages, and share artifacts and collaborate on tasks all while staying modular and sandboxed in their own environments. How does ATA work with MCP and ADK? So MCP, we've already looked at is the model context protocol, and it helps these agents work with these APIs and enterprise applications through tool discovery or resources, and other kind of database queries, et cetera. ADK over here is the agent development kit that gives you the building blocks to create and deploy agents fast. Could use other agent frameworks like Langraf and ADK is one of them by Google. ATA is basically giving each agent a passport to travel across systems and collaborate on global problems with other agents. This is the what and why of ATA. Next, we'll break down the key components of a two a and life cycle of an AA interaction from handshake to response to artifacts shape. 64. 11.3 Discovery - A2A Client, A2A Server, Agent Card: All right. So now let's dive into the core components of away, which are basically shown on this particular page as blocks. Also the full life cycle, which is basically denoted by these arrows and shows the typical flows that happen in A to a protocol communication and how all these work together to bring eta to life. So let's start with the ATA client. The 80 client is usually an app, script or another agent. It basically consumes the ATS services and hence it is called the client. The client is the one that sends the requests like tasks SEND which we look at to an AT servers URL. What is the ATs server? It exposes a set of standard STDP endpoints defined by the ATA protocol, and it's responsible for receiving requests, processing tasks, and replying with results. Next, we have the agent card. Now, here's a really cool part. Each ATA server has a metadata file known as the agent card. This is usually available at slash dot well known slash AgNTOTJSN which is basically a URL. We call this the well known URL, and it describes the agent's name and also the description, the capabilities, the skills, the endpoint URL, and any authentication that the agent might require. So this helps the client discover and understand what these agents can do through the ATA server. So a client can simply fetch the agent cards to discover a server's capabilities, and this makes the A protocol self describing and very plug and play. This is what we called discovery where the AA client discovers what different agents are available and what they can do. So now we are clear with what a client is and what a server is and how the client can discover all the different agents through the server, through the discovery flow. So as an example, you might have a client which is a personal assistant agent that's running with every user and you might have a server that exposes three different agents for this personal assistant agent. These might be to book plane tickets, to book hotels, and to book cabs. So your personal assistant agent can basically then discover through the AT server that there are these three agents for helping with travel bookings, and when the user asks the client to book a particular trip for them, this client then might then discover and use these agents to complete this trip booking. 65. 11.4 Initiation - Tasks, Messages, Parts: How does that work happen after the discovery process? This happens through tasks, and let's look at that next. So the core unit of work in A is called a task. When the client wants something done, it sends a request to start a task using either tasks Send or tasks SND subscribe. Each task has a unique ID associated with it, and it can be in multiple states. So it can be either submitted or it can be in working state or it can be on input required state or completed. Failed or canceled. The client basically sends a request to start a task, and inside the request, the client sends a message from the user role. So messages represent communication turns between the client which has the role user and the agent that's doing the work which has the role agent. And the message basically is built using parts. A part is a fundamental content unit within a message or an artifact, which we'll look at later. It can be of three types, so it can be either a text part or a file part, or it can be a data part. The file part can be basically used to represent files with inline bytes or a URI. And the data pad can be used for structured JSON example forms. In short, when the client wants something to be done, it generates a unique task ID and sends the initial user message. The task itself contains a message and the message is basically made of parts, and this officially starts a task on the As server. This is what is called as initiation, and this is one of the flows in the 80 protocol that happens after the discovery flow. 66. 11.5 Processing - Artifacts, Streaming, Push Notifications, Non-streaming: All right. So once we have the task that started, as the agent works, it may produce what we call artifacts. So these artifacts are basically structured outputs like final answers or generated files or structured data. And they also follow the same part structure that's followed by tasks and messages. So how does the ATA server communicate its updates to the client? First, is the streaming option. For long running tasks where the servers support streaming, clients can use tasks Sent subscribe to enable streaming, and the server then uses server sent events or SSE to push updates like task status, new message or the artifacts that are being generated. So the client sees the progress in real time. Alternatively, eateway also supports push notification, so the clients can set a webhook using tasks push notification slash set. The server will call back when new events occur, and this is great for integrations where polling or streaming isn't practical. So this forms one of the processing mode, which is called the streaming mode. There's also another processing mode which is called the non streaming mode, and the server does all the work and replies with the final result at the end. The choice depends upon the server capabilities and the use case, and this non streaming processing flow happens directly from the server to the client, where the server sends back this particular task to the client. 67. 11.6 Interaction - input-required state: Sometimes the agent may hit a point where it needs more inputs. In that case, it enters what we call the interaction or the input required state. In this case, the client can continue the conversation by sending more messages using the same task ID to the server to satisfy the requirement in this interaction flow. 68. 11.7 Completion Flow & Summary of A2A: Eventually the tasks will reach a state that we call as completion. So this is a terminal state and the task can either be completed, failed, or canceled. At this point, the task is done and the artifacts and message lock can be saved or displayed as needed. So that's a detailed look at the core components and life cycle of the A to a protocol. There are agent cards for discovery through the server where the client can discover what agents are available and what they can do. There are tasks and messages, including parts for communication where the clients can initiate a task with an ID and send it to the server, and this is basically the initiation flow. Then there is two modes for processing, which is the streaming mode and the non streaming mode, and the server can then basically use artifacts, which are the outputs that it generates to notify progress to the client in real time, or it can also use push notifications, and on the other side, the processing can happen through the non streaming mode where the final result with the task and the same ID can be sent back to the client. Whenever some more information is needed, the interaction flow can basically pass on more messages to the server, and then you'll have a final completion state where the task is completed. Either it's completed successfully or it gets failed or it gets canceled. ATA, in this way is what enables modular, decentralized and collaborative AI agents to work together no matter where they're hosted.