Build an AI HR Agent: Your First MCP Server Explained in 10 Minutes
In this article, we are going to build a beginner-friendly first MCP server for a real-life use case: an HR agent that can help manage employee leave.
The server architecture is straightforward. We'll have a mock database containing employee information, such as leave history and balances. We will then build an MCP server to access this database. To interact with our server, we'll use a generic MCP client. While a custom internal chatbot would be ideal, for this tutorial, we will use the Claude Desktop client to keep things simple. This client will make calls to the MCP server we are building.
Getting Started: Prerequisites and Installation
Before we begin, you'll need to install a couple of things.
- MCP Client: Install an MCP-compatible client. We'll use Claude Desktop for this guide. You can find the installer for your operating system with a quick web search.
- MCP Python SDK: Install the official Python SDK by running the following command in your terminal:
bash pip install mcp
- UV (Python Package Manager): We will use UV to set up our project. Install it via pip:
bash pip install uv
On Windows, you can also use this command in the command prompt:powershell powershell -c "irm https://github.com/astral-sh/uv/releases/latest/download/uv-installer.ps1 | iex"
Setting Up Your Project with UV
Once UV is installed, navigate to your development directory and initialize the project.
uv init my-first-mcp-server
This command creates a new directory named my-first-mcp-server
with a basic project skeleton. If you open this directory in your code editor, you will see the following structure:
main.py
pyproject.toml
README.md
Crafting the HR Agent Server
The core of our project is the MCP server logic. While you can find basic examples on the official MCP project page, we can accelerate development by using an AI assistant like Chat GPT to generate the code for our specific leave management use case.
After some prompting and refinement, here is the complete server code. Copy and paste this into your main.py
file.
from fastmcp import FastMCP
# Mock database for employee leave information
mock_employee_data = {
"E001": {
"balance": 18,
"history": [
{"date": "2024-12-25", "reason": "Christmas Day"},
{"date": "2025-01-01", "reason": "New Year's Day"},
],
},
"E002": {"balance": 20, "history": []},
}
# Initialize the MCP server
server = FastMCP(
"leave-manager",
title="Leave Management Server",
description="A server for managing employee leave requests and balances.",
)
@server.tool()
def get_leave_balance(employee_id: str) -> str:
"""
Gets the remaining leave balance for a given employee.
:param employee_id: The unique identifier for the employee (e.g., 'E001').
:return: A string stating the employee's remaining leave balance.
"""
employee = mock_employee_data.get(employee_id)
if employee:
return f"Employee {employee_id} has {employee['balance']} days of leave left."
return f"Employee {employee_id} not found."
@server.tool()
def apply_for_leave(employee_id: str, leave_dates: list[str], reason: str) -> str:
"""
Applies for leave for a given employee on specified dates.
:param employee_id: The unique identifier for the employee.
:param leave_dates: A list of dates for the leave period in 'YYYY-MM-DD' format.
:param reason: The reason for the leave request.
:return: A confirmation message indicating the leave has been applied.
"""
employee = mock_employee_data.get(employee_id)
if not employee:
return f"Employee {employee_id} not found."
num_leave_days = len(leave_dates)
if employee["balance"] >= num_leave_days:
employee["balance"] -= num_leave_days
for date in leave_dates:
employee["history"].append({"date": date, "reason": reason})
return f"Successfully applied for {num_leave_days} day(s) of leave for employee {employee_id}."
else:
return f"Error: Insufficient leave balance for employee {employee_id}."
@server.tool()
def get_leave_history(employee_id: str) -> list:
"""
Retrieves the leave history for a given employee.
:param employee_id: The unique identifier for the employee.
:return: A list of dictionaries, each containing leave date and reason.
"""
employee = mock_employee_data.get(employee_id)
if employee:
return employee["history"]
return []
@server.resource()
def greeting() -> str:
"""A simple greeting resource."""
return "Hello! I am the HR Leave Assistant. How can I help you today?"
Note on Docstrings: The docstrings for each tool are critical. They guide the MCP client's LLM, helping it understand what each function does and how to call it correctly with the right parameters.
Connecting the Server to Your Client
With the server code ready, run the following command in your project directory to register it with your MCP client:
uv mcp install main.py
This command installs the leave-manager
server into your Claude Desktop configuration.
To ensure the client can see your local server, you may need to enable Developer Mode. This option is usually found in the client's settings. Once enabled, you can navigate to File > Settings > Developer
. You should see a leave-manager
tab. Clicking "Edit Config" will open a JSON file containing the server's configuration, which was added by the uv mcp install
command.
The configuration tells the client that a server named leave-manager
exists and can be started using the uv
command.
A Note on Potential Issues
If you encounter a TypeError
related to the typer
library during installation, running an upgrade should resolve it:
bash
pip install --upgrade typer
After a successful installation, the tools (get_leave_balance
, apply_for_leave
, get_leave_history
) will be visible in your client's interface.
Putting Your HR Agent to the Test
Now, let's interact with our new HR agent.
Query 1: Check Leave Balance You can ask a natural language question:
You: How many leaves are available for employee E001?
The client's LLM is smart enough to map this question to the get_leave_balance
tool and supply E001
as the employee_id
.
Agent: Employee E001 has 18 days of leave left.
Query 2: Check Leave History The agent maintains context. You can ask a follow-up question:
You: For the same person, let me know the exact dates when they took the leave.
Agent: They took a leave on Christmas Day (2024-12-25) and New Year's Day (2025-01-01).
Query 3: Apply for Leave Let's try applying for leave. The LLM can parse complex requests, including dates.
You: Employee ID E002 would like to apply for the 4th of July holiday. Please apply for this leave.
The agent correctly identifies the apply_for_leave
function. It parses "4th of July" into the required YYYY-MM-DD
format specified in the docstring.
Agent: Successfully applied for 1 day(s) of leave for employee E002.
Query 4: Verify the Change Finally, let's confirm the leave was deducted.
You: How many leave days are remaining for E002?
Agent: It has 19 days leave.
That's it! You have successfully built and tested your first MCP server. Feel free to experiment further with this code.
Join the 10xdev Community
Subscribe and get 8+ free PDFs that contain detailed roadmaps with recommended learning periods for each programming language or field, along with links to free resources such as books, YouTube tutorials, and courses with certificates.