-
Notifications
You must be signed in to change notification settings - Fork 210
Expand file tree
/
Copy pathcourse2_script.txt
More file actions
47 lines (36 loc) · 102 KB
/
course2_script.txt
File metadata and controls
47 lines (36 loc) · 102 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Course Title: MCP: Build Rich-Context AI Apps with Anthropic
Course Link: https://www.deeplearning.ai/short-courses/mcp-build-rich-context-ai-apps-with-anthropic/
Course Instructor: Elie Schoppik
Lesson 0: Introduction
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/fkbhh/introduction
Welcome to MCP: Build Rich-Context AI Apps with Anthropic built in partnership with Anthropic. In this course, you'll learn the core concepts of MCP and how to implement it in your AI application. The Model Context Protocol, or MCP, is an open protocol that standardizes how your LLM applications can get access to context in terms of tools and data resources based on the client-server architecture. It defines how communication takes place between an MCP client hosted inside your own LLM application, and an MCP server that exposes tools and data resources and prompt templates to your application. Since Anthropic launched MCP in November of 2024, the MCP ecosystem has been growing really rapidly. I'm delighted that the instructor for this course is Elie Schoppik, who is Head of Technical Education at Anthropic. Thanks, Andrew. I'm excited to teach this course with you. MCP originated as part of an internal project where we recognized an opportunity to extend the capabilities of Claude Desktop so that it can interact with local file systems and other external systems. We found the protocol we developed was useful in many AI applications, with similar needs. To make this available to more developers, we published the specification and opened its development to the open source community. The MCP ecosystem includes a growing number of MCP service developed by the open source community, as well as by Anthropic's MCP team. MCP is model agnostic and is designed to be easy to plug into multiple applications. Say you're building a research assistant agent, and you'd like for this agent to interact with your GitHub repos, read notes from your Google Drive documents, maybe create a summary stored in your local system. Instead of you writing your own custom LLM tools, you can connect your agent to the GitHub, Google Drive and File System service, which will provide the tool or the API call definitions and also handle the tool execution. Elie will walk you through the details of the MCP protocol. We'll first dive into the details of the MCP client-server architecture. You'll then work on a chatbot application to make it MCP compatible. You'll build and test an MCP server and connect your chatbot to it. Your MCP server will provide tools, prompt templates, and resources to your chatbot. You'll also connect your chatbot to other trusted third-party servers to extend its capabilities. You'll then re-use your MCP server and connect it to other MCP applications like Claude Desktop. Finally, you'll learn how you can deploy your MCP server remotely. I'd like to thank from DeepLearning.AI, Hawraa Salami, who had contributed to this course. MCP is a really important technology that's making it much easier for LLM application developers to connect the systems to many tools and data resources. And for teams building tools or providing data, it is also making it much easier to make what they build available to many developers. So this is a technology worth learning about. The next video goes through why connecting LLM applications to resources had been so difficult before, and how MCP addresses this. So, please go on to the next video to learn more.
Lesson 1: Why MCP
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/ccsd0/why-mcp
In this first lesson, we'll go through how MCP makes AI development less fragmented and how it standardizes connections between AI applications and external data sources. Let's go. To answer the question why MCP or why the Model Context protocol? We like to say the models are only as good as the context provided to them. You can have an incredibly intelligent model at the frontier, but if it doesn't have the ability to connect to the outside world and pull in the data and context necessary, it's not as useful as it can possibly be. The Model Context Protocol is an open-source protocol that standardizes how your large language model connects and works with your tools and data sources. The idea here is not to reinvent the wheel and how we do things like tool use, but instead to standardize the way that our AI applications connect with data sources. The same way that we standardize how web applications communicate with back ends and other systems using REST, where we specify the protocol and statelessness and so on, we're trying to achieve the same thing with the Model Context Protocol. Everything that you're going to see with MCP can be done without MCP, but as we think about a world in which many different models communicate with many different data sources, and even with each other, we want to make sure that we're speaking the same language. We want to standardize how our AI applications interact with external systems, instead of building the same integration for a different data source over and over and over again, depending on the model or the data source, we're instead going to build once and use everywhere. The Model Context Protocol borrows a lot of its ideas from other protocols that aim to achieve similar kind of ideas. For example, LSP, or the Language Server Protocol developed in 2016 by Microsoft, standardizes how integrated development environments interact with language-specific tools. When you create extensions for particular languages for particular development environments, you don't want to have to write that over and over again for all of those development environments. So while MCP is very novel and what it's trying to do, it stands on the shoulders of many other protocols and ideas around standardization. Let's go show a quick demo where with just a few lines of code, we can bring in context to our AI application. On the left-hand side here, I'm using Claude Desktop, and I'm asking a question about retrieving some issues from a GitHub repository. On the right we can see this GitHub repository. And immediately through natural language I'm able to talk to this data source. This is the power of MCP. I have connected to an MCP server that's providing data necessary from GitHub, and I'm also connected to another MCP server for Asana, a popular project management tool. What I'm doing here is reading data from GitHub, and then I'm asking to triage particular issues and assign tickets in Asana. So I am reading from one data source and writing to another. We can see here in this interface there there's a human in the loop verifying the actions that I want to take with just very little code, I'm now communicating with external data sources with ease. This idea of being able to use MCP with any model provider completely open source, allows for seamless integration with different models and different data sources. We can see here I've created these tasks. Things are updating for me in the browser, and I can now continue to use natural language to iterate on this task I have here. I'm going to assign a task to an individual. I'm going to see that get updated and through the use of a very intelligent model, in this case, 3.5 Sonnet, a few tools provided by MCP, and an environment to run this over and over again, we're actually taking a look at a very lightweight agent to power this application. Like I mentioned, everything you could do with MCP, you could do without. But here's what it starts to look like. As you build these integrations where do you store your tools? Where do you store custom prompts that you have? Where do you store that data access layer and authentication logic? We found ourselves and for many different teams, repeating the wheel over and over and over again, many different AI applications, talking to a similar data source but written in a different way. With MCP, not only is this model agnostic, it's completely open source, so these tools and data connectivity are provided to you by the open source community, or you can build them yourself. With MCP, we shift the burden of responsibility and we separate our concerns in a really clean fashion. We build or use MCP compatible applications and connect to many different servers for the particular kind of data access that we need. We can have servers for data stores, for customer relationship management tools like HubSpot or Salesforce, even servers for things like version control. And the aim here is to use natural language to talk to these data stores without having to write all that logic ourselves. With MCP, the beauty of the server is that it's also reusable across many different applications. As we're going to see, there are reference servers that we can use or servers that we can even build internally and share amongst many different applications that we build. We might build a MCP server or use one for Google Drive, and depending on the application that we're building, that could be an AI assistant or agent or desktop application as long as it is MCP compatible, we can go and use that server and whatever else we want. You can let your imagination really start to carry you with all the different data access that you can bring in to your application, with minimal code and effort. With MCP, there are lots of wins for many different audiences. For application developers, connect to an MCP server with very little work. For API developers, build the MCP server once and adopt it everywhere. For users of AI applications, the idea behind MCP can be abstracted away quite a bit, so that you can bring a URL for an MCP server and simply have the data access that you need brought into your application. For enterprises and large organizations, you can think of the benefits of separating your concerns and building standalone integrations that different teams can use. As you might be aware, the MCP ecosystem is growing fast. We're seeing development not only from large companies, but also startups at the frontier. And we're seeing many, many, many different servers being built privately and in the open source community. The SDK or software development kits that we have to power MCP are written across many different languages and developed in the open source community, and also led by many different companies and AI developers. We're seeing MCP compatible applications across web applications, across desktop applications, and even agentic products as well. Before we wrap up, let's answer a couple of common questions you might be having about MCP. These MCP servers that we talk about, from GitHub to Asana to Google Drive. Who actually writes those? Well, anyone can. You yourself as a developer can build them, or you can go ahead and use community adopted ones. In the next few lessons, we'll see how MCP servers are built, and we're going to build quite a few of our own. You might think of MCP servers as very similar to working with APIs, and in fact you're not totally off. You can think of an MCP server as kind of like a gateway or a wrapper on top of an API, where if you do not want to bother calling the API directly, you can use natural language and let the MCP server handle that for you. MCP servers support tool use, but that's just one part of what MCP servers can do. The servers give you functions and schemas available to you, but as we're going to see in the next lesson, there's so much more that MCP provides. So we answer the question why the Model Context Protocol? We've seen a really nice demo for what it can do with a very little amount of work. And the next lesson we're going to start to explore how MCP works a bit under the hood and introduce the idea of hosts and clients and servers, and talk a little bit about some of the underlying primitives in the protocol, like resources, tools and prompts. See you then.
Lesson 2: MCP Architecture
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/xtt6w/mcp-architecture
MCP is based on a client-server architecture. In this lesson, we'll go through the features that MCP can provide and how the communication between the client and the server takes place. All right. Let's dive in. So we previously spoke about why the Model Context Protocol is so useful for building AI applications and connecting to external data sources. Now let's dive a little bit deeper into the architecture behind MCP. Similar to other protocols, MCP follows the client-server architecture, where we have MCP clients that maintain a 1 to 1 connection with MCP servers. The way these two communicate with each other is through messages defined by the MCP itself. These clients live inside of a host. This could be something like Claude desktop or Claude AI. The host is responsible for storing and maintaining all of the clients and connections to MCP servers. We'll see this in a little more depth. Hosts are LLM applications that want to access data through MCP. The servers are lightweight programs that expose the specific capabilities through the protocol. And very soon we're going to start building our own servers. We'll then build our own clients as well as hosts that contain multiple clients. The code for that is going to be a little bit more lower level. But the goal here is really to understand the architecture. And when you use tools like Claude Desktop or Cursor or Windsurf, you have an idea of what's happening under the hood. So how does it work? Before we discuss the responsibilities of the client and the server, let's dive into some of the primitives or fundamental pieces of the protocol. Starting with tools. If you're familiar with tool use, tools in MCP are going to look very similar. Tools are functions that can be invoked by the client. These tools allow for retrieving, searching, sending messages, and updating database records. Tools are usually meant for data that might require something like a Post request or some kind of modification. Resources are a bit more similar to a Get request. Resources are read-only data or context that's exposed by the server. Your application can choose whether to consume or use these resources, but it doesn't necessarily have to bring it into context. Examples of resources can include database records, API responses, files, PDFs, and so on that you may have. The third primitive we're going to explore, is a prompt template. And prompt templates aim to achieve a very reasonable task, which is to remove the burden of prompt engineering from the user. You might have an MCP server whose job is to query things in Google Drive and summarize and so on, but the user itself would need to write the prompt necessary to achieve all of those tasks in the most efficient way possible. Instead of mandating that the user write the entire prompt and figure out the best practices for prompt engineering, prompt templates are predefined templates that live on the server that the client can access and feed to the user if they so choose. We're going to see in a few lessons how to build tools, resources, and prompt templates both on the server and the client. The client's job is to find resources and find tools. The server's job is to expose that information to the client. Now that we have an idea of some of these primitives: tools, resources, prompts, let's go explore what this actually looks like. I'm going to be using a host Claude Desktop, and I'm going to connect to an MCP server for SQL Lite that exposes tools, resources, and prompts. So let's take a look at that right here in Claude Desktop I've connected to an MCP server and I have tools at my disposal to work with SQLite. We'll talk a bit about the configuration settings in a later lesson. I wanted to show you what this looks like in action. Once I connect to this MCP server, I can start talking to my data in natural language. So I'll ask right after that what tables do I have and how many records are in each table. This right here is Claude connecting to the Outside World. We can see here we're going to be using a tool from the SQL light server called List Tables. You can see in the request there's no dynamic data being sent. And I'll go ahead and allow this. The ability to require a human in the loop is based on the interface that the host develops. So the server itself is simply sending back the tools. The client is then taking advantage of those tools and executing the data necessary. We can see here for the number of records that we have 30 products, 30 users and zero orders. So we can see the records that we have in this table. What we can start to do now is something a little more interesting. By taking advantage of tools like artifacts and making this slightly more visually appealing. So generate an interesting visualization based on the data in the products table. You can imagine even with my spelling mistake, we'll be able to query that information that we need. So we'll go find the table. We'll run the necessary query and fetch the data necessary. We'll see here we're going to analyze this. And it's going to tell us many things are price but there are a few higher-priced items. We're going to use the analysis tool to analyze this data. What we're bringing in here is context to an AI application. This could be Claude desktop. This could be with any other model. This could be in any other environment. But through MCP we can build really interesting applications right off the bat. I'm making use of the artifacts feature in Claude so that we can see a nice little visualization. But the goal here is really to let your imagination carry you where you can go with this. Bringing in external data. External systems allows you to easily create much more interesting, compelling, and powerful applications. We'll see here the code generated. It's going to be a nice little visualization. I have a distribution. I have price versus quantity and so on. And right after that, I can take this data that I want and turn it into something meaningful. We're doing this through tool use. So the first primitive that we've explored are the tools given to us by the MCP server. Next, let's explore some other primitives. I'm going to see here in SQLite that there is an MCP demo prompt. This is a prompt template that is being sent from the server, where all I have to do as the user is pass in some dynamic data. So here we're demonstrating what we can do with this particular prompt. This is a topic to see the database with initial data. So let's go ahead and seed the database with some data around planets. When I add this to the prompt we can see right off the bat there is a text file that's generated with a prompt that the server has given me. We can see right here this is not something that I, as the user, have to write. I just choose the dynamic data and then I go ahead and run that particular prompt. What we're going to see here is this prompt in action. And here this is going to generate a business problem and analyze some data and set up information and so on. But you can imagine giving your users much more battle tested evaluated prompts so you don't have to do it yourself. You'll see here we're going to set up some tables. We're going to query. We're going to populate all kinds of actions we can take based on the prompt and the tools that we have at our disposal. So here you're seeing an example of tools and prompts being integrated together to make AI applications far more powerful than they are out of the box. In a few lessons, we're going to start making our own prompts, our own resources, and our own tools to see how this happens under the hood. As we go through, we can actually see that there is a data insight here, a business insight memo that gets updated as we are constantly adding more data. This is an example of a resource. Resources are dynamic. They can be updated as data changes in your application. And instead of requiring tools to fetch this information, we have data here that can constantly be updated. I could ask to update the memo. I could ask to update information inside based on new data that I've achieved. So in this little example we've seen a host Claude Desktop. We've seen a variety of tools from the SQLite MCP server, and we've seen prompts and resources that allow us to perform really powerful actions. Now that we've seen what it looks like to use tools with MCP servers, let's go ahead and talk about how you actually create these. MCP provides software development kits for building servers and clients in quite a few languages. In this course, you'll be using the Python MCP SDK, which makes it very easy to declare tools, resources, and prompts. You can see here to declare a tool. We decorate a function. We pass in the necessary arguments and return values so that the tool schema can be generated. And then we return what happens when that tool needs to be executed. For resources, we allow the server to expose data to the client. And that's done by specifying a URI or a location where the client goes to find that data. You can call this whatever you want, but you can imagine to return a list of documents, this is a pretty good one. If you're sending back a certain data format, you can specify that with the main type. You decorate a function which returns the data that you want when that resource is accessed. And you can do that for direct resources. Or if you happen to have some kind of dynamic information or ID, you can go ahead and use a templated resource, just like an F string in Python. To give you an example of what an interface might look like with a resource. You can have a command line application where you use an @ sign to then fetch all the documents that you need, or for a templated resource, you can reference that directly and inject that into a prompt or request that's coming in. With resources, we don't need tools to fetch the data that we need. The server simply sends the data back to the client, and the application chooses to use that data or not. Lastly, let's talk about prompts. Just like you saw with decorating tools and resources, we do the same thing with a prompt. We give it a name and description, and then a list of messages or text to return back. With prompts, you define a set of user assistant messages or just the text of a prompt that you need. You can imagine a situation where a user might want to convert some data to markdown, and while this is a fine prompt, it might be a lot nicer if you gave them a thoroughly evaluated prompt instead. So with prompts and prompt templates, the idea is for these to be user controlled, where a user chooses to not have to do all the prompt engineering themselves, and use the quality ones provided by the server. Now that we have an idea on some of the primitives, let's talk a little bit about the communication between clients and servers. When the client opens up a connection to the server, there's an initialization process where a request is sent, a response is sent back, and a notification is sent to confirm initialization. Once that initialization appears, there's an exchange of messages that happen. It's important to look at these steps because in the code you're actually going to see methods like initialize. So make sure you understand these ideas under the hood. So when we start writing code you can understand what's happening. In message exchanges, clients can send requests to servers. Servers can send requests to clients, notifications can also be sent back and forth. We'll talk a bit later on about some of the other protocols, where servers can sample or request information from clients, and notifications can be sent both ways. Finally, at the end of communication, there's a termination of that connection. As we talk a little bit more about the connection and the way in which messages are sent back and forth. It's important to understand another part of the Model Context Protocol, and that is the idea of a transport. And a transport handles the mechanics of how messages are sent back and forth between the client and the server, depending on how you're running your application. You will choose one of these different transports. You can also make your own if you would like. For servers running locally, we're going to be using standard IO or standard input output. When we start deploying servers remotely later on in the course, we have the choice between using HTTP and server-side events or using the Streamable HTTP transport. As of this time of recording, Streamable HTTP is not supported yet across all software development kits. So we're going to be talking in depth about it. But in our example we'll be using HTTP with server center events. To give you a little bit of a distinction, when you're using HTTP, which servers and events you need to open up a stateful connection that maintains a back-and-forth that's open. For certain kinds of applications and deployments, or stateless deployments, this does not suffice. So in a newer version of the specification, the Streamable HTTP transport allows for stateful connections as well as stateless. To talk about our first transport standard, IO. The process involves the client launching the server as a subprocess, and the server reading and writing alongside the client with standard in and standard out. All of this is going to be abstracted away from us, but it's important to understand when using standard IO that this is most commonly what's done when running servers locally. When we talk about the transports or remote servers, you'll see that there are different transports based on different versions of the protocol. The original transport for remote servers involved using HTTP and server events for a stateful connection. In a stateful connection, the client and the server are communicating with each other with no closed connection between requests. Data can be shared. Data can be sent and remembered between different requests. With the ability to introduce state. In server sent events, the server is also able to send back events and messages back to the client. While this can work for a variety of applications, many applications when deployed are not stateful nor need to be stateful. In fact, it is sometimes more efficient for scaling applications to have servers that are ephemeral or stateless, where each connection and each request is different and not remembered to support both stateful and stateless connections. Updated versions of the protocol included a new transport called Streamable HTTP, which allows for making use of HTTP with server events for stateful connections or standard stateless connections with HTTP on its own. Going forward, the Streamable transport is what is going to be recommended and used so that you can support stateless connections as well as stateful connections. The way that this works is by using HTTP, get and Post requests to some endpoint. In this case, we have /MCP to initialize the request and the server returns a response. If we want to opt into or upgrade to server-sent events, we can go ahead and issue an optional Get request and send notifications back and forth. Otherwise, we make Post requests and we issue responses. In this lesson, you've seen quite a bit. From the architecture behind MCP, with clients and servers and hosts to demos making use of some of the most popular primitives like tools, prompts and resources. You saw some of the different transports and mechanisms for sending data, and now it's time for you to get your hands on some code. In the next lesson, we're going to take a look at some functionality and some tools that we'll be using. And then we're going to start layering on MCP logic to build our own servers and eventually clients and hosts. See you then.
Lesson 3: Chatbot Example
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/hg6oi/chatbot-example
Now it's time to start coding. In this lesson, you'll build a chatbot and code its tools. Before you start working with MCP, let's make sure you have a good foundation with tools use and prompting large language models. All right, let's code. So let's get started building our chatbot. And before we hop into building MCP servers, we're going to start just by building a very simple application with a chatbot that makes use of archive for searching for papers and finding some information. If this is information that you're already familiar with, feel free to skip this lesson and hop into building your first MCP server. So let's get started by bringing in some libraries that we need. So we're going to bring in the arxiv SDK. This is going to allow us to start searching for papers. We're then going to bring in the JSON module for some formatting the OS module for environment variables. We're going to bring in a little bit of typing so we can type our code. And then we'll make sure we bring in the Anthropic SDK. I'm going to first start by defining a constant here called paper directory, which is just going to be the string papers. And this is what I'm going to be using for saving information to the file system. I'm then going to bring in my first function here. So let's go take a look at this. This function is called search papers. And it accepts some kind of topic and a number of results which defaults to five. And what I'm doing here is searching for papers on archive. And if you're not familiar with Archive is an open source repository of many different published papers across a variety of domains, from mathematics to science to many different disciplines. So we're going to search for some papers, and then we're going to return a list of paper IDs. And we're going to then use those paper IDs in another function to get more detail and summarization. We're going to initialize our client. And then we'll start searching for relevant articles. We'll take the results of those search and we'll go ahead and create a directory if it exists already, great. If not, we'll go ahead and make it. And we'll save this information to a file called papers info dot JSON. What we're going to do is process each of these papers and create a dictionary. And then we're going to go ahead and write that to our file. This is going to give us back some IDs when we're done. Let's go ahead and search for some papers for computers. We'll see here. This is being saved to a file locally. And we got a bunch of IDs that we can use to get some more information around. We're going to go ahead and bring in our second function here now to make use of this paper ID. So we're going to define another function here called extract info. Which is going to take in one of these paper IDs it's going to look in our papers info JSON and give us back some information about that paper. And if it can't be found we'll go ahead and just return a string. There's no saved information for that paper. So I'm going to go ahead and grab this first ID right here. Let's go ahead and run this function. And then we'll go ahead and call this function with that particular ID just to show you what this looks like. We can see right here we're getting back some data not only related to the title of this, but also the URL for the PDF as well as a summary of this particular paper. We're going to start with these two functions. And then we're going to go ahead and start bringing in these functions as tools for a large language model. So what we're going to be able to do is pass in some tools for Anthropic's Claude model. We're then going to go ahead and build a small chatbot that takes in these tools and knows when to call them and return the data, particularly for these functions. So let's define our tools list. If you are familiar with tool use, this should be nothing terribly new, but every single tool that you make is always going to have a name and a description and then some kind of schema that it needs to follow. So in this case, we have a tool for search papers and a tool for extract info. Remember that the model itself is not going to call these functions. We actually need to write the code to call those functions and pass the data back to the model. But these tools are going to allow the model to extend its functionality. So instead of saying I don't know or hallucinate, we're going to get back the answer that we want here. So let's go ahead and start writing some of our logic for working with our large language model and executing these tools. Let's bring in a little bit of mapping for our tool. And right here we've got a function that is going to map the tools that we have to calling that underlying function. What you can see here is we have a dictionary for each of our tool names. These refer to the functions that we have below. And then a handy helper function to then go ahead and call that particular function and return the result to us in a variety of data types that come in. Let's go ahead and start building in our chatbot right now. That's going to start by bringing in any environment variables that we have API keys, and then creating an instance of our Anthropic client. We're going to need this so that we can go ahead and make calls to our model and get back some data. Let's go ahead and bring in our boilerplate function to go ahead and start working with the model. If you've worked with Anthropic before or many other models, this is going to look very familiar. We're going to start with a list of messages. We're going to go ahead and pass in the query that the user puts in. I'm going to talk to Claude 3.7 Sonnet right now. We're going to go ahead and start a loop for the chat. And if there is text data put that into the message. If the data that's coming in is tool use, if the model detects that a tool needs to be used, we're going to go ahead and bring in our helper function for executing the tool and then appending that tool result to the list of messages. Let's go ahead and see this in action. Bring in our chat loop. We've got all the functionality we need to start working with tool use talking to our model. Now let's start with a very simple example for what it's going to look like to actually use this function. We're going to run an infinite loop until we pass in the string quit. So let's go ahead and start talking to our large language model. Call our chat loop function. Right now we can start putting in a query to start talking to our model. So let's start with something very simple, like just saying hi and make sure this works as expected. We can see the model here is going to let us know not only that it's an AI assistant, but also let us know some of the tools that it has available. This is excellent. So let's go ahead and start making use of these tools. Let's search for recent papers on a topic of interest. So why don't we go and search for papers on algebra. And this should make use of the tool that we have to go ahead and search for papers. We can see that topics being passed in and the results are saved here. This is great. It's even following up with would you like me to extract more detailed information. So I'll go ahead and say yes please extract information on the first two you found and summarize them both for me. So what we're going to do is make use of that tool result that we got before. And we're going to pass that in and it's going to tell us which IDs it's interested in. So I'm going to make sure that I pass in those particular IDs so I can get that correctly done. The IDs are here. So we're going to see here it's going to extract the info with these particular IDs. And we're going to go ahead and get the result as well as a summarization here. So we got some information about in variant algebras and deformation of algebras. Honestly, I cannot tell you what this is. But hopefully I can read the paper and get up to speed on what this information has. Something to remember is that there is no persistent memory here, so as you go ahead and search for queries and get IDs, nothing is going to be stored permanently. So just make sure as you keep querying, you're passing in those IDs and think of each conversation as brand new each time. If you ever want to get out of this chat, remember we can always type in quit. So make sure you run that and we'll see that we're all done here. So what we've seen in this lesson is a review of large language models, tool use and making use of the archive SDK. What we're going to see shortly is how we can refactor this code to turn those tools into MCP tools to allow for a server to pass that information to us. We're then going to test that server and see what the results look like. I'll see you in the next lesson.
Lesson 4: Creating An MCP Server
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/dbabg/creating-an-mcp-server
You'll now take the tools you implemented for the chatbot and wrap them in an MCP server using the standard IO transport. You'll use fast MCP, which provides a high level interface to build an MCP server. Finally, you'll use the MCP inspector to test your server. Let's get coding. So we're going to pick up where we left off with the last lesson where we defined two functions, search papers to go ahead and find papers on archive. And then another function that we had down here, extract info. We took these functions and we defined them as tools and passed them to our large language model. What we're going to do now is abstract away the definition of these tools and the schema of these tools, and create an MCP server and use a library called fast MCP to help us build that quickly. So with just a few lines of code, we're going to bring in fast MCP We're going to define each of these functions as tools using MCP. And then we're going to go ahead and start our MCP server and test that in the browser. So the first thing I'm going to do is bring in the necessary import that I need. So from MCP dot server dot fast MCP I'm going to import the fast MCP class. I'm then going to go ahead and initialize that MCP server. So I'll initialize our fast MCP server. And I'll declare a variable here, which is the result of initializing that. I'll give this server a name. We'll call this research. And let's go ahead and make use of that MCP variable. As we saw before, there are quite a few primitives in the Model Context Protocol. We saw tools, resources, prompts. And what we're going to start with right now is just defining a tool. And that's as easy as decorating this function with MCP dot tool. We'll go ahead and make sure we do that for our function below as well. And what this is going to do is define two tools on our MCP server that we can start running and testing. One last thing we need to do here is make sure that we have the right command to start this server. So what I'm going to bring in is a very standard bit of Python. We're going to say if __name__ is equal to __main__, this allows me to run this directly. And if there are imports, this code does not run. I'll go ahead and initialize and run the server. I'll do that by calling MCP dot run. And I'm going to pass in a transport. As we saw before, we can run servers locally and we can run them remotely. And when we're running our servers locally we almost always use standard IO. So I'll pass in a transport of standard IO. And that's all we need to start writing our MCP server. You can see at the top here we've got a magic function to go ahead and actually write a file called Research Server dot py. So I'm going to go ahead and execute this cell. And we're going to see that we write a file called Research server dot py. This Python file is going to be used when we start our MCP server. So let's go ahead and set up our environment and test our server. To do this I'm going to go ahead and open up a new terminal. In the environment that we're in, we're going to need this code necessary to create and run code inside of a terminal. If you want to run this code locally on your own machine, you're more than welcome to do so as well. We can see here, I've got a terminal and I'm going to CD into a folder called MCP project where my code lives. I can see here I have my research server dot py. In fact, this research server dot py is all of the code that we just created above. What I need to do here is install the necessary dependencies to start working with MCP, as well as install the archive SDK. What I'm going to do here is instead of using Pip, I'm going to use a package manager called UV. UV is slightly faster than Pip and provides quite a few other nice tools to make it easier to manage your dependencies in Python. Once I run uv init, we're going to see I have initialized project called MCP project based on the name of the folder. If you're familiar with virtual environments or creating a virtual environment, this part is going to look familiar if you're not familiar with virtual environments, they're simply ways to self-contain the dependencies that you have. So that you're not installing things globally and potentially conflicting with other installations. So let's go ahead and create our virtual environment using uv venv We'll see here we have a virtual environment and actually a folder called Dot venv Let's go ahead and activate this virtual environment. We'll do that using source dot venv Then activate. And I'm using tab completion here. So I don't make any spelling mistakes. We can see here now that we're in a virtual environment called MCP project. And now we need to install the necessary dependencies. I'll clear so you can see what we have at the top. And I'll go ahead and bring in the dependencies of MCP and arxiv. We'll give this a second to install. And we're going to pull in these dependencies so that when we start running our MCP server we get the correct information. The next step right now is to test our server file. Instead of just running this code in Python, to test the server, we're going to use a tool developed called the Inspector, which gives us a browser-based environment to explore the tools, resources, prompts, and other primitives that we have. I'll clear here so we can start from the top. In order to use that tool, I'm going to run the command npx at Model Context Protocol slash inspector. What this is going to do is pull in the command to start this server so that I don't have to install it locally. And then the command that I want to use to run the application is uv run research server. I'm using, uv run so I can sure I have the correct dependencies and I'm in my virtual environment. This simply makes it an easier way to run Python files. We'll see here that we're starting our MCP inspector and the MCP inspector is up and running. So I'm going to head over to the browser and hop into that particular inspector that we're looking at. When we take a look at this inspector, we're going to see that we have a few different kinds of transport types. We have server-sent events and Streamable HTTP, our remote protocols. But remember our server is running on standard IO. So let's keep that as is. The command that we use to run is uv run research server.py. We saw in the command line that's what we passed in and that's being applied right here. One small note, since we're running this in a slightly different environment, we're going to have to paste in a proxy address that we've provided in the notebook. If you're running this locally this is not something you'll have to do. So I'm going to go ahead and paste in that proxy address. And let's go ahead and connect to our server. Once we connect, we're going to see some of the primitives that we have access to. We discussed resources, prompts, and tools and what we've created on this server right now are just some tools. But what I do want you to see is this initialize process right here. If you remember back in our previous lesson when we spoke about communication and the transports, the first process was a handshake or initialization from client to server. We're going to head over to tools, and we're going to go see what tools we have available. This list tools is another command we can issue to go ahead and find the particular tools that the server is providing. We can also go ahead and run these tools. So what's really nice about the inspector is without building any kind of MCP client or host, you have a sandbox to play around with the tools or prompts or resources that the server is returning. We can also see here from the docstring, we've inferred a description as well as the parameters that are required. Let's go ahead and search for a topic. I'll go search for chemistry and let's look for one result. When I run that tool, we're going to go ahead and get back the return value. So we have not yet added any kind of large language model or functionality here. We're simply just testing the MCP server. I can go ahead and test my other tool with that paper ID, and we should expect that I get back a success as well. The MCP inspector is extremely valuable as you start building servers, and even when you install servers that other people have written, it's a great way to have a sandbox to play around once you're done using the inspector, we can head back to our notebook and if you need to quit the server, you can stop that process using Control+C. And we're back in the terminal. If you ever need to start that again, you can always press up to get access to your previous command, so you don't have to take the whole thing. In the next lesson, we're going to start layering on an MCP host and a client and integrate this MCP server with a chatbot that we build all talking with MCP. See you there.
Lesson 5: Creating An MCP Client
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/pnd5n/creating-an-mcp-client
With your MCP server ready, it's now time to create an MCP client inside your chatbot. To let the chatbot communicate with the server and get access to the tool definitions and results. Let's have some fun! Now that we've seen how to build a server with MCP, let's go ahead and move past the inspector and build our own host to contain a client to talk to our MCP server. We're going to be working with the chatbot directly, but if you want to take a look at other files like the server that we've made before, feel free to do so. We're going to start by revisiting what we saw before in our chatbot example. You're going to see a lot of this code again, but we're going to layer on a little bit more as we start bringing a client into the mix. Everything you're seeing here we've seen before. This is simply the ability to process a query using Claude 3.7 Sonnet, as well as tool use. We can see here that we're not actually defining any tools. That's all being done in the server that we made in the last lesson. Let's go ahead now and start talking about how to bring in and create an MCP client. I'm going to bring in a bit of code from the underlying MCP library, because I want to talk through what's actually happening here. If you remember, when we create an MCP client, which lives inside of a host, we need to make sure that that client establishes a connection to an MCP server. An important note here, the code that we're looking at is slightly lower level. You won't always find yourself building clients from scratch, but it's really important that when you see other tools like Claude desktop or Claude AI, you have an idea of what's happening under the hood. So if this code looks relatively intimidating, don't be too worried. We'll go step by step. The goal here is really to make sure you understand how clients are created and how they establish connections to servers. What we're seeing here are a few imports from the underlying MCP library, to bring in the necessary classes, to establish a connection to a server, as well as the ability to start a subprocess from the client. So the first thing we're going to do here is establish the server and the parameters necessary that we want to connect to. And this is actually going to look pretty familiar. That scene command that we ran, uv run Research Server dot py. We're specifying here to let our client know how to start the server. If there are any environment variables that we need, we can pass those in here. The next step is to actually establish that connection and launch the server as a subprocess. Since we might not want this to be blocking, we're going to be making use of async and await quite a bit in Python. If you're not too familiar with that, no worries, I'll walk you through what needs to be done here. We're going to define a function called run, and we're going to set up a context manager to first pass in the parameters from our server and establish a connection as a subprocess. Once we've established the server to connect to, we're going to get access to a read and write stream that we can then pass to a higher level class called the client session. In this client session, when we pass the read and write stream, we'll get access to an underlying connection that allows us to make use of functionality for listing tools, initializing connections, and doing quite a bit more with other primitives. The first thing we're going to do is establish that handshake and initialize our session. Well, then go ahead and list all of the available tools that the server is providing. Remember, the client's job is to query for tools and take those tools and pass them to a large language model. We'll make use of our chat loop functionality that we saw before. And if there is a tool that needs to be invoked, we'll go ahead and let the MCP server do that work. So we're going to see a slightly different bit of code for executing the underlying tool. We're going to bring in the tools from the MCP server. And if a tool needs to be executed, we'll let the MCP server know what to do. And we've defined all the code necessary in the previous lesson for what happens when that tool is executed. Since we're working in an async environment, we're going to be moving past MCP dot run and using async IO dot run. So with that in mind, let's put this all together. We're going to go ahead and add our MCP client to our chatbot. We're going to go ahead and write a file called MCP chatbot dot py. Since this is what we're going to run in the terminal to start interacting with our chatbot, we're going to bring in all of the imports that you saw before alongside nest async IO, which is necessary for different operating systems to work properly with the event loop in Python. We're going to bring in any environment variables that we have and then initialize our chatbot. When we initialize our chatbot, we don't have a current session and we don't have any tools available to us. We're going to see that once we start establishing the connection, these values will change. Our process query looks very similar to above with a slight difference of what happens when the tool needs to be invoked. We're using the session established to go back to the MCP server and execute the tool necessary. We're then going to follow similar logic for appending a message and making use of tool use that we've seen before. Our chat loop as well is going to look very similar. We're going to go ahead and keep running until someone types in quit and process that particular query whenever data comes in. To wrap this up, we're going to define a function called connect to Server and Run, which does just that. Like we saw before, we establish a connection to an MCP server. We get access to the read and write stream and the underlying session so that we can establish that connection, list the tools that we need, and then take those tools and pass them for tool use in the model. To wrap this up, we initialize our chatbot and we call our connect to server and run function. Inside of a __name__ equals __mean__ We run our main function using async IO. So let's go ahead and run this code to create the necessary MCP chatbot.py file. So let's go ahead and bring in our terminal. And we'll see here I'm in the L5 directory. I'm going to CD into the MCP project folder. And if we take a look at what I have right here, I have a virtual environment that already exists. So I'm going to go ahead and start by activating that virtual environment. Source dot venv bin activate. We're also going to need a couple other dependencies to make this project work. So I'll go ahead clear this and I'll add the Anthropic SDK, the python-dotenv module for environment variable access and nest async IO. Once I add those dependencies, I should have everything necessary to start my chatbot. Before I start the chatbot let's just make sure we see how this is coming together. When I type in uv run MCP chatbot dot py. We are going to connect to our MCP server, make use of the tools that are defined, past those tools to Claude, and then create a nice interface for us to start talking with Claude, to get access to those tools and any other data that we want. We can see here that when there is a connection, we're processing that request of list tools request. This is the underlying functionality in the protocol that allows me to pull in the tools necessary. We've connected to the server with the following tools and we can start talking to our chatbot. We can always start with something simple. Just make sure things are working. A friendly query to greet our chatbot. Now let's go ahead and make use of some of those tools that we have. So I'll ask, can you search for papers around physics and find just two of them for me? What we're going to do here is make use of those particular tools that we have. We're going to see here using the call tool request that the MCP client is sending this data to the server. The server is invoking that tool and returning it back to us. We're then using Claude with that additional context to return a nice summary to us. While we've done a little bit of lower level programing to make this work, we've started to build a foundation for something incredibly powerful. We're going to first establish multiple client sessions to allow for the use of many different MCP servers. So these can all start to work together. And then we're going to start layering on additional primitives like resources and prompts. To really see this work at a much larger scale. See you in the next lesson. And don't forget, if you ever want to get out of the chatbot, you can always type quit.
Lesson 6: Connecting The MCP Chatbot To Reference Servers
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/k0f9c/connecting-the-mcp-chatbot-to-reference-servers
In the previous lesson, you connected your chatbot to one server that you built. Now you'll update your chatbot so that it can connect to any server. You'll learn more about the reference servers developed by the Anthropic team and how you can download them. Let's get to it! So far, we've seen how to build MCP servers as well as clients and connect those on a 1 to 1 basis. Well, we want to start introducing now, is the ability to not only build multiple clients that can work with multiple servers, but also introduce the entire ecosystem of servers that exist out there. So I'm going to start here by taking a look at some of the servers that are reference servers from Anthropic on our repository. So let's go take a look on GitHub for the reference servers that we have with the Model Context Protocol. As you take a look through all of the servers here, there's a massive, massive list. So we're just going to start with the reference servers. These are ones that we have worked on and built at Anthropic. There are also many different third party servers and official integrations. Any data source that you can imagine talking to at this point probably has an MCP server. Instead of you having to download these servers and run them locally. We're also going to see how we can add the command necessary to run the server without that much hassle. The servers that we're going to be using are the fetch server, as well as the file system server. So let's take a look at the fetch server. What's so interesting about this is that if you look at the underlying source code for many of these servers, it's actually going to look pretty familiar to what you built before. We can see here that the fetch MCP server exposes tools and a prompt to us, and we can see what the installation is as well. Since this server is written in Python, we're actually going to use the uv command to directly run a command called MCP server fetch, which will run all the code necessary to download what we need and establish the connection. So instead of uv run, we're going to be using uvx. The fetch server allows us to retrieve content from web pages, convert HTML to markdown so that LLMs can better consume that content. The second server that we're going to be looking at is the file system server. And just like you can imagine, this is going to be a way for us to access our file system reading, writing files, searching for files, getting metadata and so on. We can see here there are resources and tools exposed, quite a few different tools for reading and writing files. If you take a look at the source code here, you can see that this is not written in Python. This is in fact written in TypeScript, which means instead of uvx, we're going to be using a slightly different command. If we take a look at the installation instructions to run this, the command necessary is npx /y. So that we don't need to press enter for any other installation instructions and then Model Context Protocol server file system. So similar to running uvx where we can download what we need and execute it right away, we're going to be using npx from the npm package manager. We then specify any paths that we allow for reading and writing files into. As you can see, each of these reference servers have a bit of configuration required. The name of the server, the command necessary, and so on. So what we're going to do is we're going to make some updates to our chatbot. Instead of hardcoding these server parameters. We're going to make a small JSON file that we can read from to figure out the necessary commands to interact with our servers. We'll be using the file system server, the research server that we're building, as well as the fetch server. And we'll see how we can put all three of those together to create very powerful prompts. In order to make this happen, we're going to have to go ahead and change the code in our MCP chatbot. The reference servers stay the same. Our research server stays the same, but we have to update the code a bit for our MCP chatbot. There is a good amount here that is relatively lower level and plenty of opportunity for refactoring. So I'll walk you through what we have here and I welcome any changes you'd like to make to grow this as it scales. In order to get this to work, we're going to have to set up our own JSON file to configure how we want to connect to each of the individual servers. And here's what that's going to look like. We're going to start with a little bit of JSON to contain all of our servers. Then we'll specify the name of those servers as well as the underlying command necessary. And any arguments required for the research server. This is going to look relatively familiar. And for the reference servers, since we're not downloading it and then running it locally ourselves, we're using commands like npx and uvx to run those immediately. So we're going to see this file. And you can find this file as well in your list of files for this lesson under the folder MCP project. For the File System server, if you remember, we had to specify the paths that we wanted access to. And here we're specifying a dot which means the current directory that we're in. So this is not going to be able to read or write from files or folders outside of this current directory. Now let's go ahead and take a look at the code necessary for our MCP chatbot to not only connect to multiple servers with multiple clients, but also correctly read the JSON file for the server configuration necessary. Let's go ahead and see what we need to update our MCP chatbot to handle these connections. If you take a look at the code that we have here for our MCP chatbot, there's quite a bit more happening under the hood, and especially some lower level ideas that I want you to not feel too intimidated by. The most important takeaway here is to understand how tools like Claude Desktop, Claude AI, Cursor, Windsurf, work under the hood when they set up multiple connections to multiple servers. What I'm going to do here is start by adding a little bit more to my MCP chatbot. I'm going to maintain a list of all of the sessions that I've connected to, as well as all of the tools and the particular session that that tool is related to. Again, this is not production ready. This is really just giving you a sense of how to get started. And the focus here is to make sure that we correctly map a tool to the session that we're working in. We have a type definition here, as our tools are a little bit more complex than we had before. We're going to have some similar code to connect to a server, except that since we have multiple context managers inside of an asynchronous environment, we have to set up our connection a little bit differently. So we use an async exit stack to manage our connections for reading and writing, as well as managing the entire connection to the session. Below, we're going to see some pretty familiar code. We initialize a session, we list those tools, and we take the tools and append them to our list of available tools. You can imagine that this is a function that's going to be run multiple times for each of the servers that we want to connect to. And that is exactly what we're doing down here. We're going to go ahead and read from our server config file. We're going to parse that JSON, turn it into a dictionary that we can then iterate over. And for each individual MCP server, connect to it. If you are familiar with asynchronous programing you can see that this code is blocking, and maybe you could refactor this to use async IO gather or so on. But again, the focus here is understanding conceptually what's going on and welcome any refactor as you'd like to do. Once we connect to all of these servers, we're then going to use some logic that looks pretty familiar as well. We're going to go ahead and get access to our model. We're going to pass in any information coming in from a query. And then if there is a tool that we need, we're going to go find it and call that particular tool. The rest of this logic is very familiar. The chat loop that we have is exactly as what we had before, with one small note, that when we need to go ahead and close any connection that we have. We do this using our context manager for multiple different connections. Our main function has a little bit more to allow us to connect to all of the servers that we need, and then start the chat loop. And once that's all done, we can go ahead and clean up any lingering connections that we have to these servers. And just like we had before, we're going to start this application by calling Async io dot run with our main function. So let's go ahead and write this file and we'll hop back to the terminal in the terminal here. I'm going to first CD into MCP project. And I'm going to see here that I have again a dot then folder. So let's go ahead and activate that virtual environment. Source dot venv bin activate. And then let's go ahead and run our chatbot. I'll clear so we can take this from the top. And I'll type in. You've run MCP chatbot dot py. What we're going to do here is connect to multiple MCP servers by setting up multiple clients. We can see here, we've connected to the file system with the allowed directory of the current directory we're in. We've connected with these particular set of tools. We've connected to our research server as well as the fetch server itself. We have the same exact chat interface that we had before. So I'm going to paste in this prompt where I'm going to ask it to fetch the content of the Model Context Protocol and save the content to a file called MCP summary, and then create a visual diagram that summarizes the content. So what we're going to be doing here is use a multitude of tools to fetch information and then to summarize that information. We're then going to have it draw a nice little diagram for us. So let's go take a look at what that looks like. We can see here it's saved to a file called MCP summary MD. So in our file system let's go take a look at what that file looks like. So we've got this nice little diagram here for the Model Context Protocol. This was done by fetching information from the website summarizing that information. Turning it into a nice visualization. And again we're going to see an even prettier one when we start bringing in tools like Claude Desktop. But now the UI is totally up to you for what you want to do. But you can do whatever you want with this file right now. So we've seen how a couple of these servers can work together. Let's try bringing all three together. So we'll say fetch DeepLearning.AI find an interesting term to search papers around and then summarize your findings and write them to a file called results dot txt. We're going to make use of the fetch tool here to visit a website and find the content of that website. Based on that content, we'll find some interesting terms. In this case we've got multi-concept pre-training. We're then going to go ahead and find papers related to that. We're going to take that data and we're going to write it to a file. You might not find yourself using a combination of these servers for many real-world use cases, but now your imagination can carry you. Any existing MCP server can be added with minimal configuration, and you can take the results of these different MCP servers to add all the context you need to connect models like Claude to the outside world. We can see here we've got a really nice summary. Let's go ahead and see what's been written here. So we got a very interesting result from our research. It seems that while MCP or Model Context Protocol is a very powerful tool, there also is another acronym for MCP for Multi Concept pre-training. So it looks like the model got a little bit confused here. When in doubt, this is why prompt engineering is so important. And we could even follow up with a follow of this is why you should include the Model Context Protocol and not other concepts as well. As always, if we want to leave this chat session, we can type in quit. Now that we have multiple servers connecting to multiple clients, let's start adding on a few other primitives like resources for read only data and prompt templates for the ability to generate prompts on the server that the user can use so that they don't have to write prompts completely from scratch. I'll see you in the next lesson.
Lesson 7: Adding Prompt And Resource Features
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/f2uk7/adding-prompt-and-resource-features
So far, your MCP server only provided tools to your chatbot. You'll now update your server so that it also provides resources and a prompt template. On the chatbot side, you'll expose those features to the user. Let's do it! We've already seen how to create multiple MCP clients connecting to multiple MCP servers. Now let's shift back to some of the other primitives in the protocol, like resources and prompts, and talk about how we can add that both on the server as well as on the ability of the client to consume that data. In our research server dot py. You can find all of these files in your file system. All of these files are provided to you. So what I'd love to do is walk through some of the code, both on the server side and with our clients. As we saw before, adding a tool is as easy as decorating MCP dot tool. Now let's bring in resources and prompts and we'll talk a bit how to add those. The code here right now is living on our server. And what we're going to do is bring in a couple resources for all of our particular folders, as well as any papers on a particular topic. Remember that resources are read-only data that the application can choose to use, or we can give to the model. So instead of making tools to go and fetch things from the file system the same way, we have a Get request to fetch our data with HTTP, we're going to do the same thing with resources. So on the server, I have a resource with a URI for papers colon slash slash folders to go ahead and list the available folders in the paper directory. I also have a resource here to fetch information about a particular topic. We haven't done any of the implementation yet for what this is going to look like, how it's going to be presented, or how it's going to be fetched. All we're setting up on the server are just ways to listen for requests for these particular resources. We have a little bit of string manipulation in here, as well as reading files to go ahead and fetch the data necessary with some error handling to make sure that if papers are not found, we go ahead and put that error message in. We can see here we're reading from our paper's info JSON file, and then returning a bit of text around the content that we have. Aside from our resources, we can also add prompt or prompt templates to our MCP servers. So let's take a look at the prompt that we have here. Before we dive into this code, let's remember the purpose of the primitive for a prompt template. Prompts are meant to be user-controlled. You can imagine as the user of an AI application, you don't want to have to do complex prompt engineering yourself. In fact, you may be working with a server. You may be trying to get some information, but you might not know the best way to fetch it or retrieve it based on the prompt that you have. Prompt templates are created on the server and are sent to the client so that the user can use those entire templates without having to do all the prompt engineering on their own. So instead of asking the user to just specify how to search for papers, we're actually going to provide to them a battle-tested prompt that includes the dynamic information that they can put in, like the topic or the number of papers you can imagine. We can do some pretty sophisticated evaluations and prompt engineering testing. And by the time it gets to the user, this is abstracted away. We create a prompt template by decorating a function with MCP dot prompt. And then we return what the prompt template looks like. All that we're going to do on the client side is have the user put in the number of papers, which is optional, and the topic which is going to be required. Now that we've seen what's going to be sent from the server to the client, let's make sure we figure out now how to start bringing in these resources and prompts, and how to create a UI for what the resources and prompt templates should look like. This UI that we create, this presentation that we create is completely up to you as the developer to make. What's so powerful about MCP is that it doesn't mandate that all interfaces look the same and work in same. We're simply focused on sending back data and manipulating data, and the presentation is up to the client and the host to create. So with that in mind, let's hop back to our chatbot. As we saw before, there is going to be some slightly lower level code happening here. Fortunately, it's going to be relatively similar to what we saw before. We're going to store a list of the available tools and prompts that we have, as well as all of the URIs that we have for our particular resources. We're going to see in our connect to server function that things look pretty similar to what we saw before. We're going to be using this exit stack to manage all of our connections in an asynchronous environment. We're going to initialize the session. And then instead of just getting access to the tools, we're going to do the same thing for our prompts and our resources. We're going to go ahead and use the session that we establish for each client to list the prompts, list the tools and list the resources. If that server does not provide prompts or resources, we'll handle that error and print that exception. If there are any issues connecting to the server, we'll handle that as well. Our connect to servers function looks similar to what we saw before. We're going to read our JSON file, load in all of the names of the servers and the configuration necessary. Our process query is also going to look relatively similar. We're going to go ahead and create a message with our available tools. If we're using tool use we'll append that information. And then we'll go ahead and make sure that we call the correct tool. Where things will look slightly different is where we start handling resources and prompt templates. So let's start with resources. To get an individual resource, we're going to go ahead and make sure that we're dealing with the correct URI. And once we have that correct URI, we're going to read the resource from that URI. All that we're doing here is simply printing out the content of that particular resource. But depending on your interface that you want to build, you could do whatever you want with that data. We're going to do a similar thing for listing our prompts. We're going to go ahead and find all of the available prompts that we have. And if there are any arguments that those prompts require, we're going to go ahead and show that to the user. When a prompt comes in, we're going to go ahead and execute it. We'll see shortly what it looks like for a resource and a prompt to come in for the particular session that we're in. We fetch that prompt. We go ahead and we execute that particular prompt with that query. The function here that we have for executing the prompt is going to require us to get access to the prompt name and any arguments that it might have. Once we fetch that particular prompt, we go ahead and pass it in as the content of our message, and we go ahead and process the query with those arguments. Where things look a little bit different is our chat loop. Here is where we're going to start adding in the particular user interface for getting access to our resources and our prompts. We're doing a little bit of string manipulation here, and this is totally up to you as the developer of the host and clients for how you want things to be presented. We're going to be using the @ sign to get access to a particular resource. And if we see that there is a topic that's passed in first, we'll fetch it using that URI. If we see that our query starts with a slash, this is how will denote that we're using a particular prompt. If the command is slash prompts, we'll show the user all of them. If the command is slash prompt, we'll go ahead and make sure we're passing in those arguments. To pass in those arguments, we're doing a little bit of string manipulation as well. We're looking for key-value pairs separated by an equal sign. And once we have what we need we execute the prompt. We have similar cleanup logic to what we saw before and similar logic to connect to our chatbot. That's a lot of code. So let's take a step back and then we'll see this in the terminal. So let's go ahead and get my terminal. And we'll see here, that I'm inside of the L7 folder. Just like we saw before, I'm going to CD into MCP project. I'll make sure I have my dot env folder which it looks like I do. So let's go ahead and activate the virtual environment. Source, venv bin activate. Now that we got this activated let's go ahead and run our chatbot. uv run MCP chatbot.py What we're going to see here is that we're going to connect to many different MCP servers. We have a little bit of error handling here in case these servers do not provide tools, resources or prompts. What we see here is not only the ability to make a query and talk to the large language model, but also to get access to resources that we have. If I take a look at the folders that I have, I can see here that we are reading resources at this URI, and here I have access to a folder called computers. That's because in a previous search I looked for computers. Let's go get access to those papers. And here we'll see. I have the information right up here. Instead of writing a tool to go ahead and fetch that data and requiring that the model does all that work, I now can provide this context to the model and if the model chooses to go ahead and add it to its context window, and the application requires so, I can make use of that. Let's go take a look at the prompts that I have. Remember, there's a prompt that we made on the server called Generate Search Prompt. And we can actually see that the fetch server as well provides a prompt for fetching an URL and extracting its contents as markdown. The argument here is the URL. Let's go ahead and make use of this prompt. The way to do so is to add the slash prompt command. And we'll see here that the usage requires the name of the prompt, as well as any arguments that are required. So let's go ahead and use our generate search prompt. I'll use the slash prompt command. I'll pass in the name of our prompt. And then I'll go ahead and pass in the argument that is required which is the topic. Let's go ahead and search for some papers on that. The NUM papers is optional. So I can pass in a number if I want. Or I can just default to five. So let's go ahead and use this prompt with the dynamic variable of topic that I've defined. We'll see here, we're processing that to get the prompt. And then we're generating the text necessary and executing that prompt. We'll see here, this is going to look familiar, we're talking to arxiv to get access to those particular papers. We're going to take those papers and we're going to add them to the folder that we have for math. Once this is done, I should also be able to access this data via a resource. Remember that those resources are updated dynamically as data changes in my application. My query is finished and we can see the response that the model is giving me. Let's go take a look at what our folders look like. And we can see here, we now have topics for computers and math. And if we want to access that file, we can go ahead and take a look at what's there. We're making use of prompts and resources together. In this lesson, we've done quite a bit. We've explored how to add prompts and resources on the server and then consume them in our chatbot. We put together some of the core primitives like tools, resources, and prompts connecting to multiple MCP servers. In the next lesson, we're going to start introducing other kinds of hosts for more powerful interfaces. But with many of these ideas that we've seen before. As always, if you want to hop out, type in quit, and I'll see you in the next lesson.
Lesson 8: Configuring Servers For Claude Desktop
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/l8ms0/configuring-servers-for-claude-desktop
The MCP server you built and the reference servers you used can also be used with any other MCP compliant application. That could be an IDE for a desktop app or an agentic framework. Claude desktop is an example of such an application. In this lesson, you'll learn how to configure Claude Desktop to connect to MCP servers. Let's have some fun! So you previously seen how to build your own MCP servers and clients and use prompts, resources and tools to build pretty sophisticated applications. And I mentioned that some of that code, particularly when building clients and multiple clients, can be a bit low level. What you're going to see is the ability to use applications like Claude desktop and a variety of other agentic products, to use MCP to connect to MCP servers and abstract away some of the challenges of that lower-level coding. Right here I'm in a folder called MCP project on the desktop, and I have the research server that you made in a previous lesson. What I'm going to do now is follow the same steps to create an environment with uv and install the necessary dependencies. And then I'm going to navigate to Claude Desktop and bring in this MCP server alongside a couple other other reference servers that we've seen. So we'll start by doing uv init. I'll make sure to uv venv and I'll activate my virtual environment. I'll install the necessary dependencies that we have. So I'll go ahead and add arxiv as well as MCP. Once I've got these added, I have all of the necessary dependencies that I need to start my server, but I'm not going to run the server here. I'm going to use Claude Desktop to do that for me. The same way that we set up our own Json file for configuring how to connect to MCP servers, we're going to do something similar with Claude Desktop. In Claude Desktop, I'll head over to settings. I'll go to developer. And we can see here that I can edit a config file to start connecting to MCP servers. I'm going to go ahead and open up this JSON file. And inside here, I'm going to paste in our configuration file from before, but with a slight change. We're still referencing the name of the server and the command necessary to get the server started. What's important though, is that for our research server, I'm specifying the exact file path to go ahead and run the server. If you remember, when using standard IO and connecting locally, the client is going to start a connection and a subprocess to these servers. With this file and the Claude desktop AI application. This is all abstracted away from us. So all of that lower-level code that we were doing earlier we don't need to worry about. It's important to know how it works under the hood. But what we're doing here is that same idea multiple clients connecting to multiple servers. But all we need is the configuration file. You're also going to see in Claude desktop, what the interface looks like when working with prompts and tools and resources. Once we've modified this file, we have to close Claude desktop and reopen it so we can establish these connections. Now that I've restarted Claude Desktop, I can take a look at some of the tools I have access to. And we saw this before when exploring SQLite 3. I have my local research server with the tools that we've defined. I have my fetch and file system and I have from the research server my resource as well as my prompts. The interface for prompts and resources and tools is completely up to the developer of a tool like Claude Desktop. There are a variety of AI assistants and tools and agentic products that you can use that support the Model Context Protocol. Let's examine those. Over here on the Model Context Protocol documentation, we can see a list of applications that support MCP integrations. And a lot of this should look relatively familiar. These are some of the primitives we've explored, like resources, prompts, and tools. And in the last section, you'll learn a bit about sampling and routes other powerful primitives that are on their way to getting more and more adoption. As you can see here, there's quite a range of applications from web applications, agentic applications, command line interfaces, integrated development environments that support the model Context Protocol. You can click on any of these, discover them, and see how to start talking to MCP servers within these existing applications. What's so powerful about this idea is that while this may look extremely vast, you've actually seen already how a lot of this works under the hood by building your own servers and own clients. So let's take a look at how Claude desktop users are tools, prompts, and resources by connecting to MCP servers. Now let's put this all together. I'm going to paste in a prompt that I have here to use the fetch tool to visit DeepLearning.AI I can find an interesting topic about machine learning. I'll then use our research server to research a few papers and summarize the main topics covered. I'll then use the artifacts feature to generate a web-based quiz application with a set of flashcards based on the key topics in the papers. So what we're doing here is combining a set of tools from different MCP servers to fetch the data that we're looking for. So we're using the fetch tool here to visit DeepLearning.AI. And here, looks like there are quite a few interesting topics. One of those being multi-modal LLMs and advancements in AI models. We'll then use our search papers tool from the research server to extract some information about those papers. We'll even look at one more recent paper to ensure we have a good sample. Here, we see the two papers that have been discovered and a web application that's being built at the moment. The ability to incorporate visualizations and tools like artifacts with the tools that we get from MCP servers, allow us to build really powerful applications across a variety of domains with relative ease. While we just have a small example here, you can let your imagination carry you again for all the different use cases we have. We've got a summarization and a little game right here. We can take a look at what some of these answers are. And with a little bit of prompting, we can always make this look a little bit nicer. In this lesson, you've seen how to use tools like Claude Desktop to connect to MCP servers and abstract away a lot of the lower level networking and code. You've also seen a list of many different MCP compatible applications to get you up and running with different IDE's, web applications, and client-side or desktop applications. In the next section, we'll dive a little bit deeper into building remote MCP servers. See you then.
Lesson 9: Creating And Deploying Remote Servers
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/khdoe/creating-and-deploying-remote-servers
Your AI application can also connect. To MCP servers running remotely. In this lesson, you'll learn how to build a remote server, test it, and then deploy it. Let's jump in. So far we've seen how to build servers, build clients and hosts, but it's all been done locally using standard IO. Now let's see what it looks like to create and deploy a remote server. The good news is we don't actually have to change that much. Inside of the research server I've made a small configuration for our port to allow connecting a little bit easier. Everything else is going to feel the same. We still have our tools. We still have our resources. We still have our prompts. But where things are going to look a little bit different, is at the very bottom here, where we specify the transport that we're using. At the time of this recording, the SDK in Python don't yet support HTTP streamable. So we're going to be using SSE. The good news is once those SDKs are released, it should be a very quick change to modify the transport. Now that we've seen how to modify our research server to get up and running with SSE, let's go ahead and connect to it with the inspector. From this code that we provided, you can see that the server is already running at this particular URL. So there's nothing you need to do here to get the server up and running. Now that the server is running, let's bring in the terminal and connect to that server using the Inspector. So I'll run npx @ Model Context Protocol slash inspector. This will get the inspector started. And now I can go ahead and visit this in the browser. Over here in the inspector, I'm going to make sure that I have the proxy address that we had before. And you can find this in the notebook as well. And then I'm going to go ahead and make sure that my transport type is SSE. I'm now going to put in the URL to connect via SSE. And we provided this to you as well. Let's go ahead and connect. We can see here that we've initialized our connection. And we have our resources, prompts, tools, and other primitives. I can list my resources and take a look at all of my folders. I can list my templates to get access to a particular topic. So let's go see if we can search for math like we had before. Go ahead and run that search. For the prompts, We have our prompts available. And for tools, I have my tools available as well. Now that we're successfully connecting to this server using SSE, let's see how we can deploy this so that anyone can access our MCP server. Let's go ahead and deploy this server using a tool called render. I'll go bring in my terminal here. And right now I'm inside of the MCP projects folder. In order to work with render, I need to make sure that I have a git repository and then push that to GitHub so that render can access that particular repository. If you're not familiar with git and GitHub, I'll walk you through all those commands and what they do. If you're familiar with git, this should be a breeze. To get started with git, the first thing I'm going to do is initialize an empty git repository. I'm then going to make sure that there are some files and folders that are not included in git. So I'm going to go ahead and add the string then to a file called dot git ignore. This is going to make sure that when I add and commit files the dot then folder is not included. If I take a look at my git status right now, I can see that I don't see that dot env folder, which is great. The next thing I need to do here, is make sure that my dependencies are compatible with render. Since render does not support uv at the moment. We're going to go ahead and make sure that we use Pip instead for dependency management. We're going to have to take the dependencies for our server that we set up with uv and make them compatible with Pip. The command we want is uv pip compile. So we're going to go ahead and type in uv pip compile our pyproject .toml And what you see here is the output of turning our dependencies into what Pip needs. So we're going to take the result of that. I'm going to send it to a file called requirements.txt Now that we have that file called requirements.txt, there's one more file that we need to make sure we have the right version of Python for render to use. We're going to go ahead and send the string Python 3 11 11 into a file called runtime dot txt. Now that we have the necessary files, let's take a look at git status and we can see that now we have requirements.txt as well as runtime txt. Let's go ahead and add and commit. And here our commit message is going to be ready for deployment. And now we need to take this code on git locally and bring it into a repository on GitHub. We need a GitHub repository so that render can pick up and load the project files. So in the browser I'm going to head over to github.com slash new to make a new remote repository. And I'll give this repository a name. Let's call this remote research. I'll go ahead and create that repository. And once I've created that repository I'm just going to use these last couple steps. In order to push an existing repository from the command line, I need to know where I'm sending that to. So I'm going to go ahead and copy and paste this command and go back to the terminal to run it. If I've done that successfully, I should be able to type in git remote, dash B and C origin as well as what I put in. I'm now going to go ahead and push this code up to GitHub, so I'll type in git push origin main. If this has been done successfully, I should be able to go back to the browser. Refresh the page and see that my code is there. Now that this code is successfully on GitHub, let's go ahead and make sure that render can pull it in so we can deploy successfully. I'm going to head over to render.com And at render.com I'll make sure I sign up. Once you've signed up or signed in you can head over to your dashboard. Once I sign in to the dashboard, I can now add a new service. So I'll click on Deploy Web Service. Or I can always go to new and have that there. If I authenticate through GitHub I can put in repositories that I have. Or I can put in a public git repository if I just want to put in the URL. I'll go ahead and select remote research. And the only thing I need to change here is the command that we use to start our server. The command to do so is Python research_server.py. I'll make sure right now I'm using the free plan. And once this is done, I'm ready to deploy. This might take a little bit so give it a second while it starts the application. And as we start deploying we're going to see the commands necessary to get our application up and running. Things that we actually saw before when we were running this locally. So we can see here we're using that Python 3 11 11 that we specified in our runtime txt We're installing the dependencies from our requirements.txt file. Since we're using pip here for dependency management. Once this is deployed, when we visit this link we're not going to find anything. So we should expect a 404 error. But we do want to see is if we go to slash SSE we're seeing a response with the session ID back from the server. We're running the command Python research_server.py. So let's go ahead and see what things look like. The first time you look at this, it might take a second as your application is loading. So feel free to give it a minute or two. And we'll refresh the page. And as we refresh the page, and as expected I'm getting a 404. If I head over to the SSE endpoint, I can now see that I made it with this particular endpoint and a session ID. This means that I've deployed successfully. If you want to try this out in the Inspector or in other tools, take a look at the resources we have. Great job getting this deployed and I'll see you in the next lesson.
Lesson 10: Conclusion
Lesson Link: https://learn.deeplearning.ai/courses/mcp-build-rich-context-ai-apps-with-anthropic/lesson/algdo/conclusion
In this course, you've learned about the core concepts of MCP. You've built a server that exposes tools, resources, and prompts, developed a chatbot, that can connect to multiple servers, use Claude Desktop to build more sophisticated applications and deploy your own remote server. Congratulations! MCP is constantly evolving. In this last lesson, you'll learn about other features of MCP and some of the exciting things coming soon to the protocol. I'll see you there. There's a lot you've learned about the Model Context Protocol. You've learned about hosts and clients and servers, tools, resources and prompts. And then you've got a chance to write some code to power larger applications using all of these ideas. But there's still a bit that we have not yet covered about the model context protocol. Much of this is an active development, and you can always examine the latest on the specification, run through GitHub and through the discussions that you can find. The first piece we haven't covered yet is authentication in the Model Context Protocol. In the March specification update, OAUTH 2.1 was added as the means of authentication with remote servers. What this allows for is for clients and servers to authenticate and send authenticated requests to data sources. You can imagine many different servers need to access data that requires some form of authentication. This requires the client making a request to the server. The server then requiring some user to authenticate. And once the authentication process is successfully done, the client and server can exchange a token and the client can make authenticated requests to the server and then to the data source. This part of the protocol is an active development, and there are always newer features and security pieces being added. But authentication will primarily be done with the OAUTH 2.1 protocol. To highlight that in some depth, this is an optional feature of the Model Context Protocol, but it is highly recommended for remote servers. With standard IO, we use environment variables and don't have the need for this kind of authentication. This is built on established standards that you can take a look at with these links below. So while we've explored primitives that to be exposed by the server tools, resources and prompts, we also have primitives that the clients can expose. These include roots and sampling. Let's dive into this. A route is a URI that a client suggests a server should operate in. The idea is centered around only looking in specific folders for files that you might need. When the client connects to a server, it can declare the roots that the server should work with. This can be useful for filesystem paths, but can be any valid URI, including HTTP URLs. The benefits of roots allow for security limitations. Allow for keeping the server focused on a relevant file path or location, and roots also have some versatility baked in, where again, they're useful for file paths, but also can be any valid HTTP URI. We're slowly starting to see more and more clients adapt this primitive, and it's an important one to keep track of as the protocol evolves. The last primitive that we're going to cover is sampling. Sampling allows for servers to request inference from a large language model. Kind of like the other side of communication, where instead of the client talking to the large language model, the server can talk back to the client and request inference. An example here might be a situation where your users report that a website is slow for some reason. Your MCP server can then collect server logs, performance metrics, error logs, and communicate with a variety of data sources to see what's going on. Instead of the server handing that back to the client, putting everything in the context window, or potentially any kind of breach of security between the server and the client, the server instead can talk directly to the large language model and ask it to diagnose performance issues. The large language model analyzes the patterns and returns data back, and then the server can generate the steps to make the website a bit less slow. When there are concerns from a security standpoint or breaching boundaries. Or you might not want all that data coming back to be put into context. Sampling and creating sampling loops, it's a very powerful way for servers to request inference and kind of switch the direction of communication from what we've seen before. This is also quite powerful as we explore agentic capabilities with the Model Context Protocol. As we start to move towards a world where more models are talking to different data sources, and we're giving more autonomy to models to call different tools and go off on their own, we believe MCP will be a foundational protocol for agents. As we start to think about how MCP can be used with agentic capabilities, you can imagine a scenario where an user and a large language model need to access a variety of MCP servers. What's so powerful about the Model Context Protocol is that there's a composable and somewhat recursive nature, where clients can be servers, and servers can be clients. What this allows us to do is to start creating an architecture where we can take advantage of the ability for clients to communicate with servers, but also for servers to request the data that they need through sampling back to a client. What we've set up here is the idea of a multi-agent architecture, where the application and a large language model communicate with an agent. This agent happens to be an MCP client and a server, and it can serve data back to the application, but it can also connect to other clients and servers through the Model Context Protocol. You can imagine that we have agents for analysis, for coding, for research that also happen to be MCP servers. And if they need to connect to other servers, clients as well. Through this composable nature, we can start to think about architectures that allow for multiple agents all speaking the same language with the same protocol. The next large piece that's on the roadmap for the model Context Protocol, is the idea around a unified registry. The purpose of this is to standardize the way in which we think about discovering servers themselves. As we've seen before, there's a lot of excitement in the open source community, and there are many different servers for data providers. Tools like Google Drive, GitHub and so on may have dozens of MCP servers, but just like with packages with NPM or PyPI, there's an opportunity for malicious code to exist inside of these particular servers. So the registry API serves the purpose of discovering servers, of centralizing where these servers live, and also verifying that these servers have been trusted by the community and by companies themselves. This also allows for versioning of particular MCP servers to lock in dependencies, just like you would in your application. What this also gets exciting is the ability for MCP servers to let agents self discover them. You can imagine a scenario where a user needs to fix a bug based on something in some logs. The agent then searches through the registry API for the official MCP server, installs it and queries and suggests the fix. In this particular use case, instead of requiring the application to be connected to a variety of servers from the start, we can start to build applications where MCP servers are dynamically discovered and connected to. As we think about layering this on with authentication, we can imagine that a user has a request that requires a server to be discovered. Similar to other protocols like OAUTH and the agent-to-agent protocol that Google recently announced, the idea of putting in a JSON file in a well-known folder is something that's been done before, except here in this MCP JSON, we specify the endpoint of a server to connect to, the capabilities or primitives that it exposes, and then the authentication that's required. So a user might ask how we manage my store on Shopify. The agent or AI application will see if Shopify has a well known MCP JSON file. And if it does, it will figure out what endpoint to connect to and what authentication is required. Once the user authenticates, the agent can perform the necessary action. Through a registry API, we can allow for this idea of dynamic discovery and through layering on Oauth2, we can ensure that these connections are secure. As you might see in the suggestions, and in the discussions, there's a lot more that's coming to the protocol. As more and more clients support HTTP streamable. The aim is to achieve a smooth transition between staple and stateless capabilities. As remote MCP servers continue to be developed, it's important to expand the ecosystem to support even more and more of those. As you can imagine, when multiple MCP servers are being used, it's very possible for tools to have naming conflicts. You can imagine servers that might have generic names of tools like fetch users, fetch entities, and the model might get confused about what needs to be fetched. So it's important to think about preventing collisions and creating logical groups of servers or tools. We spoke a bit about sampling or proactively requesting context. There's a lot of work that's being put into the protocol and it's conversations we have to enable primitives like sampling to become much more popular. And finally, while OAUTH2 is relatively new to the specification, there's still quite a bit more to think about with regards to authentication and authorization at scale. In just a short amount of time, you've seen so much about the Model Context Protocol. You learn conceptually about the primitives. You've built, servers and clients and hosts, and you've seen how to deploy remote MCP servers. There's still so much more to be discovered. So I encourage all of you to take a look at the discussions and the conversations, and keep building and researching as much as you can. Thank you so much for joining me in this journey, and I can't wait to see what you build with MCP.