The complete guide to Model Context Protocol (MCP)
MCP Explained: Important Details and Step-by-Step Guide

At my core, I'm a problem solver who gets a kick out of turning ideas into reality. Software engineering is my tool of choice for making that happen—the way I bring solutions to life.
TLDR; Think of Model Context Protocol (MCP) as a “universal language” that lets different AI tools understand and work with each other. If done correctly, MCP helps AI agents to be more effective at using tools.
Introduction
You’re probably here because you’ve heard the buzz about MCP and all of a sudden, every tool you use seems to have its own MCP server. But what is MCP? How does MCP work? And like every developer would ask: “How do I build my own MCP server?” You’re in the right place. I’ve gone down the MCP (Model Context Protocol) rabbit hole to satisfy my curiosity. I’ve consolidated everything I’ve learned here so you don’t have to.
Some context on how MCP started and its current state
Here’s how everything started, Model Context Protocol emerged in November 2024 as Anthropic's open standard for connecting AI systems to external data and tools, solving what developers call the "N×M integration problem." Within six months, MCP achieved adoption by OpenAI, Google DeepMind, and Microsoft, amassing over 16,000 servers across the ecosystem. Yet beneath this explosive growth lies a more complex reality: 43% of implementations contain critical security vulnerabilities, enterprises face a steep learning curve, and the protocol itself remains in active evolution.
In this guide, I hope to cuts through the hype to deliver actionable intelligence for developers building real-world MCP implementations.
Before MCP
If you understand the problem MCP solves, its existence makes sense. Developers are used to working with APIs, where they're responsible for preparing the expected input. Take a weather API endpoint—the docs list required parameters like lat, lon, and others. Your job as a developer is to prepare your software to pass exactly what the endpoint expects. Building a weather alert app? You'd load lat and lon from user data, call the API, and return something useful.
!!! Insert diagram
Now imagine you want AI to handle this. You'd need to spell out exactly where to get the data, how to prepare it, and the conditions for each field. You'd repeat this for every single endpoint the AI needs to access. Working with 10 different API providers? Good luck—especially when one endpoint changes and everything breaks.
Why and how does MCP works?
MCP (Model Context Protocol) is a standardized way for APIs to tell AI how to use them—similar to how API documentation tells developers how to use them. The key innovation? It shifts responsibility to the API provider. Instead of developers spelling out every detail for the AI, the weather API itself now tells the AI how to use its endpoints. That's MCP.
A real-life example
Let’s take a look at Figma MCP, to really understand how MCP works.
Let's look at this open-source Figma MCP server. Here's the API endpoint developers had to work with:
// Taken from Figma-Context-MCP ./src/services/Figma.ts
/**
* Get raw Figma API response for specific nodes (for use with flexible extractors)
*/
async getRawNode(
fileKey: string,
nodeId: string,
depth?: number | null,
): Promise<GetFileNodesResponse> {
const endpoint = `/files/${fileKey}/nodes?ids=${nodeId}${depth ? `&depth=${depth}` : ""}`;
Logger.log(
`Retrieving raw Figma node: ${nodeId} from ${fileKey} (depth: ${depth ?? "default"})`,
);
const response = await this.request<GetFileNodesResponse>(endpoint);
writeLogs("figma-raw.json", response);
return response;
}
To make this useful, developers needed to build additional modules and components around it—just to get information about a single node.
With MCP: Instant Integration
Connect your AI agent to the Figma MCP server. It instantly knows what to provide to get node information. No extra setup required.

A list of MCP servers
You can get a list of MCP server here or refer to cursor mcp list. But here are a few that I personally find it useful as a developer
| Name | URL | Why Useful (For Developers) |
| Figma | https://figma.com | Figma offers responsive design, advanced component creation, interactive prototyping, and a Dev Mode for precise handoff—making it easier for developers to collaborate with designers, inspect specs, and translate design into production code efficiently . |
| Task-master | https://mcpmarket.com/task-master | Task-master automates task planning, parsing PRDs into actionable tasks, and integrates directly with MCP servers and AI-driven editors, allowing developers to streamline workflows, automate CI/CD setup, and focus on coding rather than on meta-work . |
| Context7 | https://upstash.com/context7 | Context7 plugs up-to-date, version-specific documentation and code examples into your workflow, reducing time spent on debugging and validation, thus accelerating development and lowering technical debt for both new and experienced developers . |
| Firecrawl | https://firecrawl.dev | Firecrawl enables fast, scalable web scraping and data extraction, supports turning URLs into structured LLM-ready data, automates lead enrichment, supports dynamic content and anti-bot mechanisms, and accelerates agentic AI development for research or production use . |
How to use MCP?
Using MCP with Cursor and Other AI Tools
You can use MCP with chat models (ChatGPT, Claude), AI-powered IDEs (GitHub Copilot, Cursor, Claude Code), or directly in your terminal. While setup varies by provider, the process typically follows three steps: configure the MCP, get your token, and enable it.
Setting Up Cursor MCP
Cursor maintains an official Cursor MCP list with pre-configured servers. For any MCP in this list, integration is straightforward:
Open Cursor settings using
Ctrl+Shift+P(orCmd+Shift+Pon Mac)Navigate to the Tools & MCP tab
Click the Add button next to your desired MCP server
Cursor handles the configuration automatically—no manual setup required.

Click install and you’ll see this screen next:

If you expand on the tools, you’ll see exactly what your AI agent (cursor in this case) have access to:

Now let’s get to the fun part!
Building your own MCP with FastMCP
Up to this point, we’ve talked a lot about what is mcp, why mcp and how to use it. Now let’s get our hands dirty. To start off, building an MCP server involves exposing capabilities through tools (functions that perform actions), resources (data providers), and prompts (reusable templates).
What is FastMCP?
FastMCP is a Python framework that makes it easy to build MCP servers. It has become the preferred Python frame for this task due to its significant developer experience improvements.
Why Use FastMCP?
Before MCP existed, integrating AI with APIs was painful:
Developers had to write detailed instructions for every single API endpoint
Each API required custom prompt engineering
When an API changed, everything broke
Managing 10+ different APIs? A maintenance nightmare.
With FastMCP and MCP, your server tells AI agents exactly how to use it—automatically.
Understanding MCP Server Capabilities
FastMCP lets you expose three types of capabilities:
| Capability | Decorator | Purpose | Example |
| Tools | @mcp.tool() | Functions that DO things | Generate fortune, send email, fetch data |
| Resources | @mcp.resource() | Data that can be READ | View archives, access files, read stats |
| Prompts | @mcp.prompt() | Templates that GUIDE AI behavior | Personality modes, task instructions |
Most MCP servers primarily use Tools. Resources and Prompts are optional extras for specific use cases.
Building Your First FastMCP Server
Step 0: Prerequisite
Install uv (Python package and project manager)
Create a folder with
pyproject.tomlfile
[project]
name = "a-sample-project"
version = "1.0.0"
Step 1: Install FastMCP
uv add fastmcp
After running this you’ll see fastmcp added into your dependencies array in the pyproject.toml file.
Step 2: Create Your MCP Server
Create a file called fortune_teller.py:
from fastmcp import FastMCP
mcp = FastMCP("Fortune Teller 🔮")
# TOOL: Performs an action
@mcp.tool()
def predict_fortune(name: str, category: str = "random") -> str:
"""
Generate a new fortune prediction.
Args:
name: The person's name to personalize the fortune
category: Type of fortune (career, love, money, or random)
Returns:
A personalized fortune message
"""
import random
fortunes = {
"career": [
f"{name}, your next bug fix will be legendary! 🐛→✨",
f"{name}, you'll finally understand that legacy codebase! 📚",
],
"love": [
f"{name}, you'll meet someone special in a GitHub discussion! 💕",
f"{name}, your code review will spark romance! ❤️",
],
"money": [
f"{name}, you'll find a forgotten $20 in your jacket! 💰",
f"{name}, your side project will earn DOZENS of dollars! 💸",
],
"random": [
f"{name}, your code will compile on the first try! 🎯",
f"{name}, you'll finally understand async/await! ✨",
]
}
fortune_list = fortunes.get(category, fortunes["random"])
return random.choice(fortune_list)
# RESOURCE: Provides readable data
@mcp.resource("fortune://history")
def fortune_history() -> str:
"""View all past fortune predictions."""
return """
📜 Fortune History Archive
Recent fortunes:
- Alice: Your code will compile on the first try! 🎯
- Bob: You'll find a forgotten $20 in your jacket! 💰
- Carol: Your next bug fix will be legendary! 🐛→✨
Total fortunes predicted: 1,337
Accuracy rate: 0% (but 100% entertaining!)
"""
# PROMPT: Guides the AI's behavior
@mcp.prompt()
def fortune_teller_mode() -> str:
"""Activate mystical fortune teller personality."""
return """You are a mystical fortune teller with a quirky sense of humor.
Your role:
- Greet users warmly and ask for their name
- Offer different types of fortunes (career, love, money, random)
- Deliver fortunes with emojis and dramatic flair
- Always end with "The stars have spoken! ✨"
Be entertaining, not accurate!"""
if __name__ == "__main__":
mcp.run(transport="http", port=8000)
Step 3: Understanding Your Code
Why docstrings and type hints matter:
FastMCP uses Python's introspection to automatically generate a structured manifest that tells AI agents how to use your tools. Here's what happens:
@mcp.tool()
def predict_fortune(name: str, category: str = "random") -> str:
# ^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^ ^^^
# | | | |
# Tool name Parameter Default value Return type
"""
Generate a new fortune prediction.
# ↑ Becomes the tool description
Args:
name: The person's name to personalize the fortune
# ↑ Becomes parameter description for 'name'
category: Type of fortune (career, love, money, or random)
# ↑ Becomes parameter description for 'category'
"""
FastMCP converts this into JSON Schema:
{
"name": "predict_fortune",
"description": "Generate a new fortune prediction.",
"inputSchema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The person's name to personalize the fortune"
},
"category": {
"type": "string",
"description": "Type of fortune (career, love, money, or random)",
"default": "random"
}
},
"required": ["name"]
}
}
This manifest is what AI agents read to understand your tools!
Step 4: Run Your FastMCP Server
uv run fortune_teller.py
You should see this:
╭──────────────────────────────────────────────────────────────────────────────╮
│ │
│ ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█ │
│ █▀ █▀█ ▄▄█ █ █ ▀ █ █▄▄ █▀▀ │
│ │
│ FastMCP 2.13.0.2 │
│ │
│ │
│ 🖥 Server name: Fortune Teller 🔮 │
│ │
│ 📦 Transport: HTTP │
│ 🔗 Server URL: http://127.0.0.1:8000/mcp │
│ │
│ 📚 Docs: https://gofastmcp.com │
│ 🚀 Hosting: https://fastmcp.cloud │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
[11/13/25 10:50:35] INFO Starting MCP server 'Fortune Teller 🔮' with transport 'http' on http://127.0.0.1:8000/mcp server.py:2050
INFO: Started server process [788]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Your server is now running at http://localhost:8000/mcp 🔮
Connecting FastMCP to Cursor (Cursor MCP Integration)
Now let's connect your FastMCP server to Cursor so the AI can use your tools.
Setting Up Cursor MCP
Method 1: Using Cursor's MCP Settings
Open Cursor and press
Ctrl+Shift+P(orCmd+Shift+Pon Mac)Navigate to Settings → Tools & MCP
Click New MCP Server
Update the
mcp.json
{
"mcpServers": {
"fortune-teller": {
"url": "http://localhost:8000/mcp",
"name": "Fortune Teller 🔮"
}
}
}
- Head back to the cursor settings and you’ll see this

How Cursor MCP Uses Your FastMCP Tools
Let's see what happens when you chat with Cursor after connecting your FastMCP server.
Example Conversation
You: "Can you predict my fortune for my career?"
Behind the scenes:
Cursor checks available tools
Cursor: "User wants a fortune prediction. Let me check my tools..." Found: predict_fortune from Fortune Teller 🔮 Needs: name (required), category (optional)Cursor plans the call
Cursor: "I'll call predict_fortune with: - name: 'User' (from context) - category: 'career' (user specified)"Cursor calls your FastMCP tool
{ "tool": "predict_fortune", "arguments": { "name": "User", "category": "career" } }Your FastMCP server responds
{ "result": "User, your next bug fix will be legendary! 🐛→✨" }Cursor formats the response
Cursor: "🔮 User, your next bug fix will be legendary! 🐛→✨"
The Magic: Self-Describing Tools
Your FastMCP server self-describes its capabilities. Cursor doesn't need manual instructions—it automatically knows:
What tools are available
What parameters each tool needs
What types those parameters should be
Which parameters are required vs optional
What each parameter means (from your docstrings)
Testing you FastMCP Server inside Cursor
Start a new cursor window and open up a new cursor chat. Try asking “Can you predict my fortune for my career”?

As you can see, the cursor mcp knows you is aware of your MCP can calls the right tool. Depending on your setting, cursor may ask you for permission before running it. If you accept it, here’s what you’ll see.

Testing Your FastMCP Server
You can test your FastMCP server without Cursor using the FastMCP client:
import asyncio
from fastmcp import Client
client = Client("http://localhost:8000/mcp")
# Test the tool
async def test_tool():
async with client:
result = await client.call_tool(
"predict_fortune",
{"name": "Alice", "category": "career"}
)
print(f"🔮 {result}")
# Test the resource
async def test_resource():
async with client:
history = await client.read_resource("fortune://history")
print(f"📜 {history}")
# Test the prompt
async def test_prompt():
async with client:
prompt = await client.get_prompt("fortune_teller_mode")
print(f"🎭 {prompt}")
# Run tests
asyncio.run(test_tool())
asyncio.run(test_resource())
asyncio.run(test_prompt())
Run the file with uv run test.py
Output:
🔮 Alice, your next bug fix will be legendary! 🐛→✨
📜 Fortune History Archive...
🎭 You are a mystical fortune teller...
FastMCP Best Practices for AI-Friendly Tools
Quick Rule: If a human developer would struggle to understand your function without comments, AI will too. Make everything explicit through docstrings and type hints!
| ✅ DO | ❌ DON'T |
| Write Clear Docstrings. Include purpose, parameters (Args), and return value descriptions. AI reads these to understand your tool. | Skip Docstrings. Without docstrings, AI has no context about what your tool does or how to use it properly. |
Use Type Hints. Always specify parameter and return types (name: str, age: int). This tells AI exactly what data types to provide. | Use Vague Function Names. Avoid generic names like process() or calc(). Use descriptive names like convert_markdown_to_html(). |
Use Literal for Enums. For parameters with specific valid values, use Literal["option1", "option2"] to tell AI the exact allowed choices. | Leave Parameters Untyped. Untyped parameters default to Any, making it unclear what the AI should provide. |
Use Descriptive Parameter Names. Name parameters clearly: birth_year instead of x, email_address instead of data. | Use Single-Letter Variables. Avoid unclear names like x, y, data, or input that don't explain what they represent. |
| Document Edge Cases. Explain constraints in docstrings (e.g., "Cannot divide by zero", "Date must be in ISO format"). | Assume AI Knows Context. Don't assume AI understands implicit rules or constraints without documentation. |
Conclusion
So there you have it! Model Context Protocol (MCP) in a nutshell. Instead of wrestling with endless API integrations, MCP lets your tools explain themselves to AI agents. If you've made it this far, you've got everything you need to start building. Spin up a FastMCP server, hook it into Cursor MCP, and watch the magic happen. The MCP protocol is still evolving, but with major players like OpenAI and Google backing it, this is clearly where things are headed. Don't overthink it! Start with something simple, see what MCP can do, and iterate from there. The best way to understand what MCP is all about? Build something with it. Your fortune-telling server is waiting!


