Introduction And Lesson Overview

Welcome back! In the previous lesson, you learned what the Model Context Protocol (MCP) is, why it is important, and how to launch a basic MCP server in Python using the FastMCP class. You also explored the two main ways to run your server — using standard input/output (stdio) for local communication and Server-Sent Events (SSE) for networked scenarios. By now, you should feel comfortable starting an MCP server and understanding how it fits into the broader AI integration landscape.

In this lesson, we will build on that foundation by exploring how to define and expose your server’s capabilities. Specifically, you will learn how to add tools, resources, and prompts to your MCP server. These are the core building blocks that allow your server to provide useful functions, share data, and guide AI interactions. By the end of this lesson, you will know how to define each of these primitives and how to interact with them from a client. This will prepare you to create more powerful and interactive MCP servers.

Understanding MCP Server Primitives

To make your MCP server truly useful, you need to expose its capabilities in a way that clients (such as AI agents or other applications) can discover and use. MCP provides three main primitives for this purpose: tools, resources, and prompts.

  • Tools are executable functions that perform actions or computations. For example, a tool might add two numbers, fetch data from an API, or process a file. Tools are the “actions” your server can perform on request.
  • Resources are data entities that your server exposes. These can be static (like a greeting message or configuration) or dynamic (like user profiles or database records). Resources provide context or information that clients can read and use.
  • Prompts are reusable templates that guide AI interactions. They help structure the way an AI model asks questions, explains concepts, or interacts with users. Prompts can accept arguments and generate dynamic messages.

Understanding these primitives is essential because they are the standard way for AI models and clients to discover what your server can do. When you define tools, resources, and prompts, you make your server’s capabilities visible and accessible to the outside world.

Defining MCP Tools

Let’s start by defining a tool. In MCP, a tool is simply a Python function that you expose to clients using a decorator. The FastMCP library makes this easy with the @mcp.tool() decorator. When you decorate a function as a tool, it becomes discoverable and callable by clients.

Here is an example of a simple tool that adds two integers and returns the result:

In this code, the add function takes two integer arguments, a and b, and returns their sum. The @mcp.tool() decorator registers this function as a tool with the MCP server. You can add as many tools as you like, each with its own logic and documentation.

When a client connects to your server, it can list all available tools and see their names, descriptions, and input parameters. This makes it easy for clients to discover what actions your server can perform.

Exposing MCP Resources

Next, let’s look at resources. Resources are pieces of data that your server exposes for clients to read. Each resource is identified by a unique URI (Uniform Resource Identifier), which acts like an address for that piece of data.

To define a resource in FastMCP, you use the @mcp.resource() decorator and provide a URI. Here is an example:

Notice the description parameter in the decorator. While you might expect FastMCP to use the function’s docstring as the resource description, in practice, the docstring is not always picked up reliably due to current limitations in FastMCP’s docstring parsing. To ensure your resource has a clear, visible description when clients list available resources, you should always provide the description argument explicitly in the decorator.

In this example, the greeting function is registered as a resource with the URI resource://greeting. When a client requests this resource, the server returns the string "Hello from My Server!". Resources can be static, like this greeting, or dynamic, returning different data based on input parameters or server state.

Resources are useful for sharing configuration, documentation, or any other data that clients might need to use as context for AI interactions.

Creating MCP Prompts

Prompts are a unique feature of MCP that allow you to define reusable templates for AI interactions. A prompt is a function that generates a message or instruction, often using input arguments to customize the output.

To define a prompt in FastMCP, use the @mcp.prompt() decorator. Here is an example:

In this code, the ask_about_topic function takes a topic argument and returns a formatted string asking for an explanation of that topic. Prompts like this are helpful for guiding AI models to ask questions, explain concepts, or follow specific workflows.

When a client lists available prompts, it can see their names, descriptions, and required arguments. The client can then request a prompt with specific arguments to generate a customized message.

Connecting to the MCP Server with the MCP Client

To interact with your MCP server, you can use the mcp client interface. The client connects to the server using a transport, such as standard input/output (stdio). Here’s how you can launch the server and establish a connection from a client script:

This script prepares everything needed to launch your MCP server as a separate process (subprocess) and communicate with it using standard input and output streams (stdio). The process involves several key steps to establish a working connection between the client and the server.

The main steps are:

  • Define the server parameters, including the command to run and any arguments (such as the server script filename).
  • Use stdio_client to start the server process and obtain the low-level read and write streams for communication.
  • Pass these streams to ClientSession, which manages the details of the MCP protocol, including sending requests and receiving responses.
  • Call await session.initialize() to perform the initial handshake and set up the session.

By following these steps, you ensure that both the client and server are properly connected and ready to exchange MCP messages. Only after the session is initialized can you safely make requests such as listing tools, reading resources, or calling tools on the server.

Listing Available Tools, Resources, and Prompts

Once the client is connected, it can use the list_tools, list_resources, and list_prompts methods to dynamically discover all the capabilities the server exposes. These methods are important because they allow agents to explore available actions, data, and interaction templates at runtime, enabling flexible and adaptive use of the server’s features. The following code demonstrates how to list each type of primitive and print their names and descriptions, providing a clear overview of what the server offers.

After running this code, you’ll see a summary of all tools, resources, and prompts that the server provides, making it easy to understand what actions and data are accessible:

Calling a Tool from the Server

After discovering the available tools, you can invoke any tool by name using the call_tool method on the client session. This method allows you to execute server-side functions and retrieve their results by providing the tool’s name and the required arguments as a dictionary.

For example, to call the add tool (which takes two integers and returns their sum), you can use the following code:

When you run this code, the client sends a request to the server to execute the add tool with the specified arguments. The server processes the request and returns the result, which you can access from the first element of the returned content list using the .text attribute.

Example output:

This mechanism allows clients to dynamically execute any tool exposed by the server, making it easy to integrate and automate server-side actions from your client applications.

Reading a Resource from the Server

Just as you can call tools by name and pass arguments, you can also access resources exposed by the server using their unique URIs. The example below shows how to read the resource://greeting resource and print its value. Since the server returns a list of resource instances, you access the first element’s .text property to get the actual greeting.

When you run this code, the client retrieves the greeting resource and prints its content:

Generating a Prompt with Arguments

Prompts can be used to generate dynamic messages by providing the required arguments. The following code demonstrates how to generate a prompt for a specific topic by calling the prompt with an argument and printing the resulting message. This is especially useful for guiding AI interactions or creating user-facing messages on the fly.

Here, the client sends the topic "machine learning" to the prompt and prints the generated message:

This is the power of MCP: clients can dynamically explore and use whatever tools, resources, and prompts your server provides without needing to know the details in advance.

Summary And Next Steps

In this lesson, you learned how to define and expose the three main MCP server primitives: tools, resources, and prompts. Tools let your server perform actions or computations, resources provide data for clients to use as context, and prompts guide AI interactions with reusable templates. You also saw how a client can connect to your server, discover its capabilities, and interact with each primitive.

These building blocks are at the heart of the MCP framework. By mastering them, you can create servers that are both powerful and flexible, ready to integrate with AI agents and other applications. In the next section, you will get hands-on practice by defining your own tools, resources, and prompts, and by writing client code to interact with them. Happy coding!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal