Building an MCP Server for User Management
1. Introduction
The Model Context Protocol (MCP) is an open protocol designed to make it easy for different tools, APIs, and AI agents to discover, connect, and work together—no matter who built them or where they run. Think of MCP as the universal language for automation and tool integration.
A Fitness Analogy: Imagine walking into a gym with dozens of machines, each with its own instructions and quirks. Normally, you'd have to learn how to use each one separately, and your workout would be slow and inefficient. Now imagine you have a world-class trainer (MCP) who knows every machine, understands your goals, and can seamlessly guide you from one exercise to the next, adjusting each machine for you. You just focus on the workout—the trainer handles the rest.
In the same way, MCP acts as the "trainer" for your software ecosystem. It abstracts away the complexity of connecting different tools, so you can focus on building powerful, automated workflows without worrying about the details of each integration.
2. How Does MCP Work?

The diagram above illustrates the Model Context Protocol (MCP) architecture in action, showing how different components interact to enable seamless tool integration and automation.
Key Components Explained
MCP Host
The MCP Host acts as the central orchestrator in the ecosystem. It manages and coordinates multiple MCP Clients, providing a unified interface for discovery, authentication, and orchestration. In the diagram, the MCP Host is the orange box that connects the user (at the top) to various MCP Clients. It ensures that requests from users or agents are routed to the appropriate MCP Server, and can aggregate or manage multiple clients and servers for scalability and security.
MCP Client
An MCP Client is any application or agent that interacts with MCP Servers to discover and invoke tools. In the diagram, examples include:
- Custom ChatBot
- VS Code or Copilot (with built-in MCP client)
- Claude Desktop (with built-in MCP client) Each MCP Client communicates with the MCP Host to discover available tools and send invocation requests. Clients can be user-facing (like chatbots or IDEs) or automated agents.
MCP Server
An MCP Server exposes actual tools or APIs that can be invoked via the MCP protocol. In the diagram, there are specialized MCP Servers for different domains:
- Database MCP Server (connected to RDS)
- Google Drive MCP Server (connected to Drive API)
- Slack MCP Server (connected to Slack) Each server registers its tools and provides metadata so clients can discover and use them dynamically. The MCP Server handles the execution of tool requests and returns results to the client.
Detailed Workflow

3. My MCP Server and Client Implementation
To understand MCP in practice, I implemented user management servers using both the FastApiMCP library and the native FastMCP server. This allowed me to compare two approaches for exposing tools as MCP endpoints.

FastAPI MCP Server (FastApiMCP)
In the first approach, I used FastAPI with the fastapi_mcp
library to expose user management operations as MCP tools. This server acts as a bridge between REST endpoints and the MCP protocol, making it easy to register and discover tools.
Key features:
- Exposes endpoints for listing users and registering new users
- Integrates with MCP using
FastApiMCP
- Publishes tool metadata for dynamic discovery
Example (see user-tools-mcp.py
):
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
import requests
app = FastAPI()
@app.get("/users", operation_id="getUsers", summary="this tool will give you all users")
def list_users() -> list:
url = "http://localhost:8000/users/"
response = requests.get(url)
response.raise_for_status()
return response.json()
@app.post("/users/register", operation_id="register_user", summary="this tool is used to register user")
def register_user(username: str, email: str, password: str) -> dict:
url = "http://localhost:8000/users/register"
payload = {"username": username, "email": email, "password": password}
response = requests.post(url, json=payload)
response.raise_for_status()
return response.json()
mcp = FastApiMCP(app, name="User MCP", description="Simple application to manage users")
mcp.mount()
MCP Server (FastMCP)
I also experimented with the FastMCP
server from the mcp-server
package. This approach lets you define tools directly as Python functions, register them with the MCP server, and expose them without needing a full FastAPI app.
Key features:
- Lightweight, minimal setup
- Register Python functions as MCP tools
- Supports all core MCP features
Example (see user-tools.py
):
from mcp.server.fastmcp import FastMCP
import requests
mcp = FastMCP("UserMCP")
@mcp.tool()
def register_user(username: str, email: str, password: str) -> dict:
url = "http://localhost:8000/users/register"
payload = {"username": username, "email": email, "password": password}
response = requests.post(url, json=payload)
response.raise_for_status()
return response.json()
@mcp.tool()
def get_user(user_id: int) -> dict:
url = f"http://localhost:8000/users/{user_id}"
response = requests.get(url)
response.raise_for_status()
return response.json()
@mcp.tool()
def delete_user(user_id: int) -> dict:
url = f"http://localhost:8000/users/{user_id}"
response = requests.delete(url)
response.raise_for_status()
return response.json()
@mcp.tool()
def list_users() -> list:
url = "http://localhost:8000/users/"
response = requests.get(url)
response.raise_for_status()
return response.json()
Both approaches let you expose user management as MCP tools, but FastApiMCP is ideal if you already use FastAPI, while FastMCP is great for lightweight, tool-centric servers.
4. Key Takeaways and Lessons Learned
- MCP makes tool integration easy: By exposing user management as MCP tools, I could connect my API to any MCP-compatible client or agent with minimal effort.
- FastApiMCP is great for existing FastAPI projects: If you already have a FastAPI app, adding MCP support is straightforward and leverages your existing endpoints and models.
- FastMCP is lightweight and flexible: The native FastMCP server is ideal for quickly exposing Python functions as tools, without the overhead of a full web framework.
- Tool metadata is powerful: MCP’s self-describing tool metadata enables dynamic discovery and validation, making it easy for clients and agents to understand how to use each tool.
- Chaining tools enables automation: With MCP, it’s easy to compose multi-step workflows by chaining tool invocations, enabling powerful automation scenarios.
- Error handling and feedback are important: Providing clear error messages and tracebacks (as in my implementation) helps with debugging and improves the developer experience.
5. Integrations with Existing Systems
One of the biggest strengths of MCP is how easily it can be layered on top of existing APIs and services. In my project, I integrated MCP with a pre-existing FastAPI-based user management server, allowing both traditional REST and modern MCP clients to access the same functionality.
How I did it:
- The original user management API (see
API/user_management/
) exposes endpoints for registering, listing, and managing users. - The MCP server (using either FastApiMCP or FastMCP) acts as a thin wrapper, forwarding tool invocations to the existing REST endpoints using HTTP requests.
- This approach required no changes to the original API logic—MCP simply adds a new, interoperable interface on top.
Benefits:
- You can modernize legacy APIs without rewriting them.
- Both REST and MCP clients can coexist, enabling gradual migration.
- Tool metadata and discovery become available for automation and AI agents.
Example:
# In the MCP server, forward tool calls to the existing API
@mcp.tool()
def register_user(username: str, email: str, password: str) -> dict:
url = "http://localhost:8000/users/register"
payload = {"username": username, "email": email, "password": password}
response = requests.post(url, json=payload)
response.raise_for_status()
return response.json()
This pattern can be used to MCP-enable any existing RESTful service, making it discoverable and composable in modern AI-driven workflows.
6. Conclusion
Building MCP servers using both FastApiMCP and FastMCP gave me hands-on experience with the protocol and its ecosystem. MCP makes it easy to expose, discover, and automate tools across diverse platforms, and can be layered on top of existing APIs for maximum flexibility. As the protocol matures, I expect even more powerful integration and automation scenarios to emerge.
Real-World Use Cases for MCP
- AI Agent Tooling: MCP is used by AI agents (like OpenAI GPTs, Microsoft Copilot, and Anthropic Claude) to dynamically discover and invoke tools, enabling them to automate workflows, access databases, or trigger business processes without custom integration code.
- Enterprise Automation: Companies are adopting MCP to orchestrate multi-step business processes across cloud services, internal APIs, and SaaS tools, making automation more robust and maintainable.
- Developer Productivity: IDEs and developer tools (such as VS Code extensions) leverage MCP to provide in-editor access to company APIs, documentation, and deployment tools, streamlining developer workflows.
- Cross-Platform Integration: MCP enables interoperability between different programming languages, platforms, and vendors, making it possible to compose workflows that span Python, Java, cloud APIs, and more.
For full project code, examples, and updates, see my GitHub repository: