VOOZH about

URL: https://thenewstack.io/tutorial-build-a-simple-mcp-server-with-claude-desktop/

⇱ Tutorial: Build a Simple MCP Server With Claude Desktop - The New Stack


TNS
SUBSCRIBE
Join our community of software engineering leaders and aspirational developers. Always stay in-the-know by getting the most important news and exclusive content delivered fresh to your inbox to learn more about at-scale software development.
REQUIRED
It seems that you've previously unsubscribed from our newsletter in the past. Click the button below to open the re-subscribe form in a new tab. When you're done, simply close that tab and continue with this form to complete your subscription.
The New Stack does not sell your information or share it with unaffiliated third parties. By continuing, you agree to our Terms of Use and Privacy Policy.
Welcome and thank you for joining The New Stack community!
Please answer a few simple questions to help us deliver the news and resources you are interested in.
REQUIRED
REQUIRED
REQUIRED
REQUIRED
REQUIRED
Great to meet you!
Tell us a bit about your job so we can cover the topics you find most relevant.
REQUIRED
REQUIRED
REQUIRED
REQUIRED
REQUIRED
Welcome!

We’re so glad you’re here. You can expect all the best TNS content to arrive Monday through Friday to keep you on top of the news and at the top of your game.

What’s next?

Check your inbox for a confirmation email where you can adjust your preferences and even join additional groups.

Follow TNS on your favorite social media networks.

Become a TNS follower on LinkedIn.

Check out the latest featured and trending stories while you wait for your first TNS newsletter.

PREV
1 of 2
NEXT
VOXPOP
As a JavaScript developer, what non-React tools do you use most often?
Angular
0%
Astro
0%
Svelte
0%
Vue.js
0%
Other
0%
I only use React
0%
I don't use JavaScript
0%
Thanks for your opinion! Subscribe below to get the final results, published exclusively in our TNS Update newsletter:
NEW! Try Stackie AI
From clobbered drafts to real-time sync
Apr 14th 2026 10:00am, by David Moore
TypeScript 6.0 RC arrives as a bridge to a faster future
Mar 14th 2026 9:00am, by Darryl K. Taft
Mastra empowers web devs to build AI agents in TypeScript
Jan 28th 2026 11:00am, by Loraine Lawson
2025-05-07 16:00:04
Tutorial: Build a Simple MCP Server With Claude Desktop
tutorial,
AI / AI Agents / Software Development

Tutorial: Build a Simple MCP Server With Claude Desktop

We walk you through the step-by-step process of building an MCP server and integrating it with Claude Desktop.
May 7th, 2025 4:00pm by Janakiram MSV
👁 Featued image for: Tutorial: Build a Simple MCP Server With Claude Desktop
Photo by Danielle-Claude Bélanger on Unsplash.

In the previous part of this series, I introduced the basic concepts of Model Context Protocol (MCP) — an open standard designed to streamline how AI models interact with external tools, data sources and resources. In this installment, I’ll walk you through the step-by-step process of building an MCP server and integrating it with Claude Desktop.

We’ll use Python and FastMCP 2.0 to build an MCP server that utilizes the FlightAware API. For more information on FlightAware, refer to the previous tutorial, where I integrated it with large language model (LLM) tools. Ensure that you have a valid FlightAware API key before proceeding.

In subsequent parts of this series, I’ll demonstrate how to extend this to work with AI agents built with OpenAI Agents SDK and Google Agent Development Kit (ADK).

Step 1: Setting Up the Environment

Let’s start by creating a virtual environment and installing the required Python modules:

python -m venv venv
source venv/bin/activate
pip install requests fastmcp pytz

Step 2: Building the MCP Server

First, import the required Python modules in the code:

import json
import os 
import requests
import pytz
from datetime import datetime, timedelta
from typing import Any, Callable, Set, Dict, List, Optional
from mcp.server.fastmcp import FastMCP

The next step is to create the MCP object from FastMCP:

mcp = FastMCP("Flight Server")

We’ll then create a function and decorate it with the @mcp.tool() annotation to explicitly identify it as a tool:

@mcp.tool()
def get_flight_status(flight):
 """Returns Flight Information"""
 AEROAPI_BASE_URL = "https://aeroapi.flightaware.com/aeroapi"
 AEROAPI_KEY="YOUR_API_KEY"
 
 def get_api_session():
 session = requests.Session()
 session.headers.update({"x-apikey": AEROAPI_KEY})
 return session
 
 def fetch_flight_data(flight_id, session):
 if "flight_id=" in flight_id:
 flight_id = flight_id.split("flight_id=")[1] 
 
 start_date = datetime.now().date().strftime('%Y-%m-%d')
 end_date = (datetime.now().date() + timedelta(days=1)).strftime('%Y-%m-%d')
 api_resource = f"/flights/{flight_id}?start={start_date}&end={end_date}" # Fixed & to &
 
 try:
 response = session.get(f"{AEROAPI_BASE_URL}{api_resource}")
 response.raise_for_status()
 json_data = response.json()
 
 # Print the response for debugging
 print("API Response:", json.dumps(json_data, indent=2))
 
 if 'flights' not in json_data or len(json_data['flights']) == 0:
 return None
 
 return json_data['flights'][0]
 except Exception as e:
 print(f"Error fetching flight data: {e}")
 return None
 
 def utc_to_local(utc_date_str, local_timezone_str):
 utc_datetime = datetime.strptime(utc_date_str, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.utc)
 local_timezone = pytz.timezone(local_timezone_str)
 local_datetime = utc_datetime.astimezone(local_timezone)
 return local_datetime.strftime('%Y-%m-%d %H:%M:%S') 
 
 session = get_api_session()
 flight_data = fetch_flight_data(flight, session)
 
 if flight_data is None:
 return json.dumps({
 'error': 'Failed to retrieve flight data. Check the API key and flight ID.',
 'flight': flight
 })
 
 try:
 dep_key = 'estimated_out' if 'estimated_out' in flight_data and flight_data['estimated_out'] else \
 'actual_out' if 'actual_out' in flight_data and flight_data['actual_out'] else \
 'scheduled_out'
 
 arr_key = 'estimated_in' if 'estimated_in' in flight_data and flight_data['estimated_in'] else \
 'actual_in' if 'actual_in' in flight_data and flight_data['actual_in'] else \
 'scheduled_in' 
 
 flight_details = f"""
Flight: {flight}
Source: {flight_data['origin']['city']}
Destination: {flight_data['destination']['city']}
Departure Time: {utc_to_local(flight_data[dep_key], flight_data['origin']['timezone'])}
Arrival Time: {utc_to_local(flight_data[arr_key], flight_data['destination']['timezone'])}
Status: {flight_data['status']}
"""
 return flight_details
 except Exception as e:
 print(f"Error processing flight data: {e}")
 return json.dumps({
 'error': f'Error processing flight data: {str(e)}',
 'flight': flight
 })

The last step is to create the main function to run the server if it’s executed directly:

if __name__ == "__main__": 
 mcp.run()

That’s it! We’re done building our first MCP server. It’s time to put it to the test by integrating it with Claude Desktop.

Step 3: Integrating With Claude Desktop

Ensure you have the latest version of Claude Desktop. Open the Settings menu to access the Developer tab:

👁 Image

Click on the Edit Config button to access the MCP settings file named claude_desktop_config.json.

Open the file in your favorite editor and add the following content:

{
 "mcpServers": {
 "flight": {
 "command": "/Users/janakiramm/Demo/venv/bin/python",
 "args": [
 "/Users/janakiramm/Demo/flight_server.py"
 ]
 }
 }
}

Replace the path with the absolute path to your Python environment and MCP server and save the file.

Restart Claude, and you should now find your MCP server within the settings option.

👁 Image

Make sure it’s turned on. Now we’re all set to use our MCP server from Claude.

It’s time to test the MCP server by asking Claude about a flight schedule. Claude will ask for your permission to access a third-party service.

👁 Image

Once you allow it, Claude will invoke the MCP server and fetch the data, which acts as the context to the original prompt.

👁 Image

As we can see from the output, Claude invoked the MCP server to fetch the real-time status. Note that we are using the STDIO transport.

You can find the entire code in the Gist below:

In upcoming articles in this series, we’ll explore how to use other transport protocols, including streamable HTTP transport. Stay tuned!

TRENDING STORIES
Janakiram MSV (Jani) is a practicing architect, research analyst, and advisor to Silicon Valley startups. He focuses on the convergence of modern infrastructure powered by cloud-native technology and machine intelligence driven by generative AI. Before becoming an entrepreneur, he spent...
Read more from Janakiram MSV
SHARE THIS STORY
TRENDING STORIES
TNS owner Insight Partners is an investor in: OpenAI.
SHARE THIS STORY
TRENDING STORIES
TNS DAILY NEWSLETTER Receive a free roundup of the most recent TNS articles in your inbox each day.
The New Stack does not sell your information or share it with unaffiliated third parties. By continuing, you agree to our Terms of Use and Privacy Policy.