Model Context Protocol (MCP) makes it possible for AI assistants to interact with external tools and data sources in a standardized way.
In this tutorial, we'll build a simple MCP server using FastMCP, expose it over HTTPS with LocalTunnel, and connect it to Claude as a custom connector.
Our example will be a simple note-taking server with two tools:
-
get_notes— retrieve saved notes -
add_note— add a new note
By the end, Claude will be able to read from and write to our MCP server.
🎥 Watch the Tutorial
What We'll Build
Claude
│
│ MCP
▼
HTTPS Tunnel
│
▼
FastMCP Server
│
▼
Mock Database
We'll use an in-memory list as our database for simplicity. In a real application, you could replace it with PostgreSQL, SQLite, MongoDB, or another database.
Prerequisites
You'll need:
- Python 3
- VS Code
- Node.js and npm
- A Claude account that supports custom connectors
Create a new project and open it in VS Code.
1. Create a Virtual Environment
Start by creating a Python virtual environment:
python3 -m venv venv
Activate it on macOS/Linux:
source venv/bin/activate
2. Install FastMCP
Install FastMCP using pip:
pip install fastmcp
FastMCP makes it much easier to create MCP servers in Python without implementing the MCP protocol yourself.
3. Create the MCP Server
Create a file named main.py.
Start by importing FastMCP and creating an MCP server:
from fastmcp import FastMCP
mcp = FastMCP("Simple Note Taker")
For this tutorial, we'll use a simple Python list as our temporary database:
notes = [
{
"id": 0,
"text": "Remember to deploy server"
},
{
"id": 1,
"text": "Eat Apple at 5 PM"
}
]
We now have two initial notes.
4. Create the get_notes Tool
FastMCP allows us to turn a normal Python function into an MCP tool using the @mcp.tool decorator.
@mcp.tool
def get_notes() -> str:
output = ""
for note in notes:
output += f"Note #{note['id']}: {note['text']}\n"
return output
This function loops through our notes and returns them as a string.
5. Create the add_note Tool
Next, let's create a tool that allows Claude to add a new note.
@mcp.tool
def add_note(text: str) -> str:
new_id = len(notes)
notes.append({
"id": new_id,
"text": text
})
return f"Successfully saved note #{new_id}"
The function accepts the note text, generates a new ID, stores the note, and returns a success message.
Our MCP server now exposes two tools:
| Tool | Description |
|---|---|
get_notes |
Returns all saved notes |
add_note |
Adds a new note |
6. Configure the MCP Server
We want our MCP server to run over HTTP on port 8000.
Add this to the bottom of main.py:
if __name__ == "__main__":
mcp.run(
transport="http",
host="0.0.0.0",
port=8000
)
The complete main.py looks like this:
from fastmcp import FastMCP
mcp = FastMCP("Simple Note Taker")
notes = [
{
"id": 0,
"text": "Remember to deploy server"
},
{
"id": 1,
"text": "Eat Apple at 5 PM"
}
]
@mcp.tool
def get_notes() -> str:
output = ""
for note in notes:
output += f"Note #{note['id']}: {note['text']}\n"
return output
@mcp.tool
def add_note(text: str) -> str:
new_id = len(notes)
notes.append({
"id": new_id,
"text": text
})
return f"Successfully saved note #{new_id}"
if __name__ == "__main__":
mcp.run(
transport="http",
host="0.0.0.0",
port=8000
)
7. Run the MCP Server
Start the server:
python3 main.py
FastMCP should start listening on port 8000.
Our MCP server is now running locally.
However, Claude cannot directly access localhost:8000, so we need to expose it through an HTTPS URL.
8. Create an HTTPS Tunnel with LocalTunnel
For this tutorial, we'll use LocalTunnel.
Install it globally:
npm install -g localtunnel
Then create a tunnel to port 8000:
lt --port 8000
LocalTunnel will provide an HTTPS URL similar to:
https://your-generated-url.loca.lt
Keep the LocalTunnel process running while you're using the MCP server.
Note: LocalTunnel is useful for development and tutorials. For production, use a properly hosted HTTPS endpoint with authentication and appropriate security controls.
9. Connect the MCP Server to Claude
Now let's connect our MCP server to Claude.
In Claude, open:
Customize → Connectors
Then select:
Add a custom connector
Give the connector a name, for example:
Custom Todo
For the remote server URL, enter your LocalTunnel URL with the MCP endpoint:
https://your-generated-url.loca.lt/mcp
Then click Add.
Claude will try to connect to your MCP server.
If the connection succeeds, Claude should discover the two tools:
add_note
get_notes
Approve the tools so Claude can use them.
10. Test the get_notes Tool
Go back to the Claude chat and ask:
Show me my notes.
Claude should call the get_notes MCP tool.
You should get a response similar to:
Note #0: Remember to deploy server
Note #1: Eat Apple at 5 PM
The important part is that Claude is actually calling our MCP server to retrieve this information.
11. Test the add_note Tool
Now let's add a new note.
Ask Claude:
Add a new note: Research MCP authentication.
Claude should recognize that add_note is the appropriate MCP tool and call it with the provided text.
The server will add the note to our in-memory database.
Now ask Claude:
Show me my notes.
You should now see:
Note #0: Remember to deploy server
Note #1: Eat Apple at 5 PM
Note #2: Research MCP authentication.
We've successfully created an MCP server and connected it to Claude.
How the Request Flows
Here's what happens when you ask Claude to add a note:
You
│
│ "Add a new note..."
▼
Claude
│
│ MCP tool call
▼
HTTPS LocalTunnel URL
│
▼
FastMCP Server
│
│ add_note()
▼
Mock Database
│
│ result
▼
Claude
This is the core idea behind MCP: an AI assistant can discover and interact with external tools through a standardized protocol.
From Mock Database to a Real Database
Our example uses a Python list:
notes = [...]
This is fine for learning, but the data will disappear when the server restarts.
A real application could use a persistent database such as PostgreSQL or SQLite:
FastMCP Server
│
├── get_notes()
│ │
│ ▼
│ Database
│
└── add_note()
│
▼
Database
You could also add more tools:
get_notesadd_noteupdate_notedelete_notesearch_notes
At that point, you have the foundation for a proper AI-powered task or note management system.
Production Considerations
The LocalTunnel setup is great for experimentation, but you should take additional precautions before deploying an MCP server to production.
Consider:
- Using a stable HTTPS domain
- Adding authentication and authorization
- Validating tool inputs
- Using a persistent database
- Adding logging and monitoring
- Handling errors properly
- Limiting access to sensitive tools
- Protecting sensitive data
- Adding rate limiting where appropriate
This is particularly important when an AI assistant has permission to perform actions on your behalf.
Conclusion
In this tutorial, we built a simple MCP server with FastMCP and connected it to Claude.
The process was:
- Create a Python virtual environment.
- Install FastMCP.
- Create an MCP server.
- Add
get_notesandadd_notetools. - Run the server on port
8000. - Expose the local server using LocalTunnel.
- Add the server as a custom connector in Claude.
- Use Claude to read and create notes.
The example is intentionally simple, but the same pattern can be used to expose APIs, databases, internal services, automation workflows, and other capabilities to AI assistants.
That's what makes MCP powerful: you can give an AI model access to capabilities, not just information.
If you're experimenting with MCP, start small. Build one useful tool, connect it to an MCP client, and then expand the server as your use case grows.
Top comments (0)