# Tutorial: Creating Your First Custom MCP Server Welcome! In the previous tutorials, you learned how to use agents, tools, and workflows within a Google Colab notebook. Now that you have set up a project on your local machine, it's time to learn one of the most powerful features of the Aurite framework: creating your own custom tools. In this tutorial, you will build a simple "calculator" tool server from scratch, connect it to your project, and have an agent use it to solve a math problem. **What you will learn:** 1. **What an MCP Server is** and why it's useful. 2. How to **create a simple `stdio` server** using a Python script. 3. How to **dynamically register your new server** in your project's run script. 4. How to **give an agent access to your new tools**. > 📋 **Prerequisites** > This tutorial assumes you have successfully completed the **[Package Installation Guide](../../package_installation_guide.md)** and have a working Aurite project folder created with `aurite init`. You should be able to run `run_example_project.py` successfully. --- ## Step 1: Understanding MCP Servers Think of an MCP (Model Context Protocol) Server as a separate program that provides new capabilities—like tools, prompts, or other resources—to your agents. The "Weather Server" you used in the example project is an MCP Server. The framework can communicate with these servers in different ways. The simplest way is using `stdio` (Standard Input/Output). This means your server is just a Python script that the Aurite framework runs directly. They communicate by sending messages back and forth through the terminal, all managed by the framework automatically. ## Step 2: Create Your Custom Server Let's create a simple server that provides basic math tools. First, inside your project folder (e.g., `my_first_aurite_project`), create a new folder named `custom_mcp_servers`. Next, inside this new `custom_mcp_servers` folder, create a new Python file named `calculator_server.py`. Your project structure should now look like this: ```tree my_first_aurite_project/ ├── config/ ├── custom_mcp_servers/ │ └── calculator_server.py <-- YOUR NEW FILE ├── example_mcp_servers/ ├── run_example_project.py └── ... ``` Now, open `calculator_server.py` and add the following code: ```python # custom_mcp_servers/calculator_server.py import logging from mcp.server.fastmcp import FastMCP # Set up basic logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # 1. Create the MCP server instance mcp = FastMCP("Calculator Assistant") # 2. Define a tool using the @mcp.tool() decorator @mcp.tool() async def add(a: int, b: int) -> int: """ Adds two integers together. Args: a: The first integer. b: The second integer. Returns: The sum of the two integers. """ logger.info(f"Adding {a} + {b}") return a + b @mcp.tool() async def subtract(a: int, b: int) -> int: """ Subtracts the second integer from the first. Args: a: The first integer. b: The second integer. Returns: The result of the subtraction. """ logger.info(f"Subtracting {a} - {b}") return a - b # 3. Allow the script to be run directly if __name__ == "__main__": mcp.run() ``` This script does three key things: 1. It creates a `FastMCP` server named "Calculator Assistant". 2. It defines two functions, `add` and `subtract`, and exposes them as tools using the `@mcp.tool()` decorator. The function's docstring and type hints are automatically used to tell the agent how the tool works. 3. The `if __name__ == "__main__":` block allows the Aurite framework to execute this file as a standalone script. ## Step 3: Modify the Run Script Now that we have a server, we need to tell our Aurite application how to find and use it. We will do this by modifying `run_example_project.py`. Open `run_example_project.py` in your editor. You will see a section labeled `--- Dynamic Registration Example ---`. This is where we'll add our code. We need to do three things: 1. Import the `ClientConfig` model. 2. Define a `ClientConfig` for our new calculator server. 3. Create a new agent that uses this server. Modify `run_example_project.py` to look like the following. Pay close attention to the comments marking the changes. ```python import asyncio import logging from termcolor import colored from aurite import Aurite # CHANGE 1: Import ClientConfig from aurite.config.config_models import AgentConfig, LLMConfig, ClientConfig logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) async def main(): """ A simple example demonstrating how to initialize Aurite, run an agent, and print its response. """ from dotenv import load_dotenv load_dotenv() aurite = Aurite() try: await aurite.initialize() # --- Dynamic Registration Example --- # 1. Define and register an LLM configuration llm_config = LLMConfig( llm_id="openai_gpt4_turbo", provider="openai", model_name="gpt-4-turbo-preview", ) await aurite.register_llm_config(llm_config) # CHANGE 2: Define and register our new calculator server mcp_server_config = ClientConfig( name="my_calculator_server", # This path is relative to your project root server_path="custom_mcp_servers/calculator_server.py", capabilities=["tools"], ) await aurite.register_client(mcp_server_config) # CHANGE 3: Define and register an Agent that uses the server agent_config = AgentConfig( name="Math Agent", system_prompt="You are a math assistant. Use the tools you have to solve the user's math problem.", # Tell the agent to use our new server! mcp_servers=["my_calculator_server"], llm_config_id="openai_gpt4_turbo", ) await aurite.register_agent(agent_config) # --- End of Dynamic Registration Example --- # CHANGE 4: Update the query and agent name for our test user_query = "What is 123 + 456?" agent_result = await aurite.run_agent( agent_name="Math Agent", user_message=user_query ) print(colored("\n--- Agent Result ---", "yellow", attrs=["bold"])) response_text = agent_result.primary_text print(colored(f"Agent's response: {response_text}", "cyan", attrs=["bold"])) except Exception as e: logger.error(f"An error occurred during agent execution: {e}", exc_info=True) finally: await aurite.shutdown() logger.info("Aurite shutdown complete.") if __name__ == "__main__": asyncio.run(main()) ``` ## Step 4: Run It! You're all set! Now, go to your terminal. Make sure you are in your project's root directory (e.g., `my_first_aurite_project`) and your virtual environment is active. Run the script: ```bash python run_example_project.py ``` You should see output where the agent thinks, decides to use the `add` tool, and then gives you the final answer. ``` ... INFO:root:Calling tool: add with args: {'a': 123, 'b': 456} INFO:calculator_server:Adding 123 + 456 ... --- Agent Result --- Agent's response: 123 + 456 is 579. ``` *(Note: The exact text response may vary, but the numerical result should be correct.)* ## Further Reading: The Model Context Protocol (MCP) This tutorial uses `FastMCP` to quickly create a server, but the Model Context Protocol is a rich specification with many more features. If you want to dive deeper into how it works, check out the official documentation: * **[MCP Introduction](https://modelcontextprotocol.io/introduction)**: A high-level overview of what MCP is and the problems it solves. * **[Server Quickstart](https://modelcontextprotocol.io/quickstart/server)**: A fast-paced guide to getting a server running. Skip the first step related to uv commands, this is the equivalent of the package installation guide that you have already completed. * **[MCP Server Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/index)**: The detailed technical specification for building MCP servers. * **[Building with LLMs Tutorial](https://modelcontextprotocol.io/tutorials/building-mcp-with-llms)**: A tutorial on how to build more advanced MCP servers that interact with LLMs. --- ## 🎉 Congratulations! You have successfully built and integrated your own custom MCP server! You've taken a huge step from being a user of the framework to being a developer who can extend its capabilities. You now know how to: - Write a simple Python script to serve tools. - Configure that script as a `ClientConfig` in your project. - Give an agent access to your new tools by referencing the server's name. ### Next Steps Now that you can build and integrate your own tools, the next step is to learn how to run your agents in a more direct and powerful way using the Aurite Command-Line Interface (CLI). * **[Continue to Tutorial: Using the Aurite CLI](./08_Using_The_CLI.md)**