Skip to content

Commit 3d4ffd6

Browse files
Merge pull request #318 from jeremiaswerner/weather-mcp-server
change MCP server example from ascii_art to weather_api
2 parents d496e2a + 7f70421 commit 3d4ffd6

18 files changed

Lines changed: 529 additions & 104 deletions
Lines changed: 108 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
FastMCP — Fast, tiny MCP server example
2-
======================================
1+
FastMCP — Weather MCP Server
2+
============================
33

44
Overview
55
--------
6-
This directory contains a minimal FastMCP server example and a companion client. FastMCP demonstrates a tiny, runnable implementation of an MCP-compatible service (Model Context Protocol) intended for local testing and quick deployment to cloud platforms.
6+
This directory contains a FastMCP weather server example and a companion client. The server provides real-time weather information and forecasts using the free Open-Meteo API. It demonstrates a practical implementation of an MCP-compatible service (Model Context Protocol) for weather data, intended for local testing and quick deployment to [IBM Cloud Code Engine](https://www.ibm.com/products/code-engine).
77

88
![](./images/architecture.png)
99

@@ -32,40 +32,84 @@ Why Code Engine?
3232
- **Simple deployment**: Integrates with container registries and CI/CD pipelines.
3333
- **Managed endpoint**: Provides a secure http endpoint with a managed certificate.
3434

35-
A very tiny MCP Server
36-
----------------------
35+
Weather MCP Server Features
36+
---------------------------
37+
38+
The server provides three weather-related tools:
39+
40+
1. **search_location**: Search for locations by name to get coordinates
41+
2. **get_current_weather**: Get current weather conditions for specific coordinates
42+
3. **get_weather_forecast**: Get weather forecast for 1-16 days
3743

3844
The Python source code for the MCP server is located in [./server/main.py](./server/main.py):
3945

4046
```python
4147
from typing import Any
4248
from fastmcp import FastMCP
43-
from art import text2art
49+
import weather_api
4450

45-
mcp = FastMCP("My FastMCP Server on Code Engine")
51+
mcp = FastMCP("Weather MCP Server on Code Engine")
52+
53+
@mcp.tool
54+
async def search_location(query: str) -> str:
55+
"""
56+
Search for a location by name to get coordinates for weather queries.
57+
58+
Args:
59+
query: The location name to search for (e.g., "London", "New York", "Tokyo")
60+
61+
Returns:
62+
A formatted string with matching locations and their coordinates
63+
"""
64+
try:
65+
data = await weather_api.search_location(query)
66+
return weather_api.format_location_results(data)
67+
except Exception as e:
68+
return f"Error searching for location: {str(e)}"
4669

4770
@mcp.tool
48-
def ascii_art(input: str) -> str:
49-
"""Take an arbitraty input and return it as an ASCII art banner"""
50-
51-
if input == "Code Engine":
52-
response = ". ___ __ ____ ____\n"
53-
response += "./ __)/ \\( \\( __)\n"
54-
response += "( (__( O )) D ( ) _)\n"
55-
response += ".\\___)\\__/(____/(____)\n"
56-
response += ".____ __ _ ___ __ __ _ ____\n"
57-
response += "( __)( ( \\ / __)( )( ( \\( __)\n"
58-
response += ".) _) / /( (_ \\ )( / / ) _)\n"
59-
response += "(____)\\_)__) \\___/(__)\\_)__)(____)\n"
60-
else:
61-
response: str = text2art(input)
62-
63-
return response
71+
async def get_current_weather(latitude: float, longitude: float) -> str:
72+
"""
73+
Get the current weather conditions for a specific location.
74+
75+
Args:
76+
latitude: The latitude of the location (e.g., 51.5074 for London)
77+
longitude: The longitude of the location (e.g., -0.1278 for London)
78+
79+
Returns:
80+
A formatted string with current weather information
81+
"""
82+
try:
83+
data = await weather_api.get_current_weather(latitude, longitude)
84+
return weather_api.format_current_weather(data)
85+
except Exception as e:
86+
return f"Error getting current weather: {str(e)}"
87+
88+
@mcp.tool
89+
async def get_weather_forecast(latitude: float, longitude: float, days: int = 7) -> str:
90+
"""
91+
Get the weather forecast for a specific location.
92+
93+
Args:
94+
latitude: The latitude of the location
95+
longitude: The longitude of the location
96+
days: Number of days to forecast (1-16, default: 7)
97+
98+
Returns:
99+
A formatted string with daily weather forecast
100+
"""
101+
try:
102+
data = await weather_api.get_weather_forecast(latitude, longitude, days)
103+
return weather_api.format_weather_forecast(data)
104+
except Exception as e:
105+
return f"Error getting weather forecast: {str(e)}"
64106

65107
if __name__ == "__main__":
66108
mcp.run(transport="http", host="0.0.0.0", port=8080)
67109
```
68110

111+
The weather API functions are separated in [./server/weather_api.py](./server/weather_api.py) and use the free Open-Meteo API (no API key required).
112+
69113
Deploying the server to Code Engine
70114
----------------------------------
71115

@@ -99,20 +143,21 @@ https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp
99143

100144
Testing the deployed server with call_tool.sh
101145
---------------------------------------------
102-
The `call_tool.sh` script provides a quick way to test your deployed MCP server directly from the command line. It demonstrates the complete MCP protocol flow:
146+
The `call_tool.sh` script provides a quick way to test your deployed MCP server directly from the command line. It demonstrates the complete MCP protocol flow with weather data for Stuttgart:
103147

104148
1. Initializes an MCP session with the server
105149
2. Lists all available tools
106-
3. Calls the `ascii_art` tool with "Code Engine" as input
107-
4. Displays the ASCII art output
150+
3. Searches for Stuttgart location
151+
4. Gets current weather for Stuttgart (coordinates: 48.7758, 9.1829)
152+
5. Gets 7-day weather forecast for Stuttgart
108153

109154
Run the script from the `mcp_server_fastmcp` directory:
110155

111156
```bash
112157
./call_tool.sh
113158
```
114159

115-
The script will automatically connect to your deployed FastMCP application and execute a test call. You should see output similar to:
160+
The script will automatically connect to your deployed FastMCP application and execute weather queries for Stuttgart. You should see output similar to:
116161

117162
```
118163
FastMCP application is reachable under the following url:
@@ -122,16 +167,32 @@ initialize session
122167
Session initialized: <session-id>
123168
124169
List tools
125-
Call tool 'ascii_art' with input 'Code Engine'
126170
127-
. ___ __ ____ ____
128-
./ __)/ \( \( __)
129-
.( (__( O )) D ( ) _)
130-
.\___)\\__/(____/(____)
131-
.____ __ _ ___ __ __ _ ____
132-
.( __)( ( \ / __)( )( ( \( __)
133-
..) _) / /( (_ \ )( / / ) _)
134-
.(____)\\_)__) \\___/(__)\\_)__)(____)
171+
==========================================
172+
WEATHER TOOLS DEMONSTRATION FOR STUTTGART
173+
==========================================
174+
175+
1. Search for 'Stuttgart' location
176+
Stuttgart, Baden-Württemberg, Germany (lat: 48.7758, lon: 9.1829)
177+
178+
2. Get current weather for Stuttgart
179+
Current Weather:
180+
Condition: Partly cloudy
181+
Temperature: 15.2°C
182+
Feels like: 14.8°C
183+
Humidity: 65%
184+
Wind Speed: 12.5 km/h
185+
Precipitation: 0.0 mm
186+
187+
3. Get 7-day weather forecast for Stuttgart
188+
Weather Forecast:
189+
190+
2026-03-20:
191+
Condition: Partly cloudy
192+
Temperature: 8.5°C - 16.2°C
193+
Precipitation: 0.2 mm (probability: 20%)
194+
Max Wind Speed: 18.5 km/h
195+
...
135196
136197
SUCCESS
137198
```
@@ -147,7 +208,7 @@ Example `claude_desktop_config.json` entry that point to your deployed applicati
147208
```json
148209
{
149210
"mcpServer": {
150-
"ASCII Art FastMCP (Code Engine)": {
211+
"Weather FastMCP (Code Engine)": {
151212
"command": "npx",
152213
"args": [
153214
"mcp-remote",
@@ -164,21 +225,20 @@ Save settings and restart Claude Desktop; the remote MCP server should appear as
164225

165226
You can now chat with the MCP Server, e.g.
166227

167-
**_"Create ASCII art for: Hello, World!"_**
228+
**_"Get the current weather and forecast of New York using the tool deployed in Code Engine :-)"_**
168229

169-
Claude will detect the tool and call the `ascii_art` function, responding with ASCII art output for your input text.
230+
Claude will detect the appropriate weather tools and call them to provide current weather conditions or forecasts for the requested locations.
170231

171232
![](./images/claude_chat.png)
172233

173-
Note, the LLM even detected the simplicity of our MCP Server.
174-
175234
Building and using the Python client
176235
-----------------------------
177-
The `client` directory contains a small Python client to exercise the server.
236+
The `client` directory contains a small Python client to exercise the weather server.
178237

179238
1. Create a virtual environment and install dependencies:
180239

181240
```bash
241+
cd client
182242
python3 -m venv .venv
183243
source .venv/bin/activate
184244
pip install -r requirements.txt
@@ -192,8 +252,13 @@ Start the client by replacing the application URL from above as the `MCP_SERVER_
192252
MCP_SERVER_URL="https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp" python client.py
193253
```
194254

255+
The client will demonstrate all three weather tools using Stuttgart as an example location:
256+
- Search for Stuttgart location
257+
- Get current weather for Stuttgart
258+
- Get 7-day weather forecast for Stuttgart
259+
195260
3. Inspect and adapt
196-
- Open `client.py` to find example calls. The client is intentionally minimal so you can adapt it to your tooling or CI.
261+
- Open `client.py` to find example calls. The client demonstrates how to use all weather tools and can be adapted to query different locations or forecast periods.
197262

198263

199264
What's next?
Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,16 @@ curl -s -X POST $url/mcp \
7575
"params": {}
7676
}' | grep "data" | sed s/"data: "//g | jq .
7777

78-
print_msg "\nCall tool 'ascii_art' with input 'Code Engine'"
79-
text=$(curl -s -X POST $url/mcp \
78+
# Stuttgart coordinates
79+
STUTTGART_LAT=48.7758
80+
STUTTGART_LON=9.1829
81+
82+
print_msg "\n=========================================="
83+
print_msg "WEATHER TOOLS DEMONSTRATION FOR STUTTGART"
84+
print_msg "==========================================\n"
85+
86+
print_msg "\n1. Search for 'Stuttgart' location"
87+
curl -s -X POST $url/mcp \
8088
-H "Content-Type: application/json" \
8189
-H "Accept: application/json" \
8290
-H "Accept: text/event-stream" \
@@ -86,14 +94,51 @@ text=$(curl -s -X POST $url/mcp \
8694
"id": 1,
8795
"method": "tools/call",
8896
"params": {
89-
"name": "ascii_art",
97+
"name": "search_location",
9098
"arguments": {
91-
"input": "Code Engine"
99+
"query": "Stuttgart"
100+
}
101+
}
102+
}' | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text"
103+
104+
print_msg "\n2. Get current weather for Stuttgart"
105+
curl -s -X POST $url/mcp \
106+
-H "Content-Type: application/json" \
107+
-H "Accept: application/json" \
108+
-H "Accept: text/event-stream" \
109+
-H "Mcp-Session-Id: $session" \
110+
-d "{
111+
\"jsonrpc\": \"2.0\",
112+
\"id\": 1,
113+
\"method\": \"tools/call\",
114+
\"params\": {
115+
\"name\": \"get_current_weather\",
116+
\"arguments\": {
117+
\"latitude\": $STUTTGART_LAT,
118+
\"longitude\": $STUTTGART_LON
92119
}
93120
}
94-
}' | grep "data" | sed s/"data: "//g | jq ".result.content[0].text")
121+
}" | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text"
95122

96-
echo -e $text
123+
print_msg "\n3. Get 7-day weather forecast for Stuttgart"
124+
curl -s -X POST $url/mcp \
125+
-H "Content-Type: application/json" \
126+
-H "Accept: application/json" \
127+
-H "Accept: text/event-stream" \
128+
-H "Mcp-Session-Id: $session" \
129+
-d "{
130+
\"jsonrpc\": \"2.0\",
131+
\"id\": 1,
132+
\"method\": \"tools/call\",
133+
\"params\": {
134+
\"name\": \"get_weather_forecast\",
135+
\"arguments\": {
136+
\"latitude\": $STUTTGART_LAT,
137+
\"longitude\": $STUTTGART_LON,
138+
\"days\": 7
139+
}
140+
}
141+
}" | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text"
97142

98143

99144

ai/fastmcp-server/client/client.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import asyncio
2+
import os
3+
from fastmcp import Client, FastMCP
4+
5+
mcp_server_url = os.getenv("MCP_SERVER_URL", default="http://localhost:8080/mcp")
6+
7+
# HTTP server
8+
client = Client(mcp_server_url)
9+
10+
async def main():
11+
async with client:
12+
# Basic server interaction
13+
await client.ping()
14+
15+
# List available operations
16+
tools = await client.list_tools()
17+
print("Available tools:", tools)
18+
resources = await client.list_resources()
19+
print("Available resources:", resources)
20+
prompts = await client.list_prompts()
21+
print("Available prompts:", prompts)
22+
23+
# Stuttgart coordinates
24+
stuttgart_lat = 48.7758
25+
stuttgart_lon = 9.1829
26+
27+
print("\n" + "="*50)
28+
print("WEATHER TOOLS DEMONSTRATION")
29+
print("="*50)
30+
31+
# Search for Stuttgart location
32+
print("\n1. Searching for 'Stuttgart'...")
33+
result = await client.call_tool("search_location", {"query": "Stuttgart"})
34+
print(result.content[0].text)
35+
36+
# Get current weather for Stuttgart
37+
print("\n2. Getting current weather for Stuttgart...")
38+
result = await client.call_tool("get_current_weather", {
39+
"latitude": stuttgart_lat,
40+
"longitude": stuttgart_lon
41+
})
42+
print(result.content[0].text)
43+
44+
# Get weather forecast for Stuttgart (7 days)
45+
print("\n3. Getting 7-day weather forecast for Stuttgart...")
46+
result = await client.call_tool("get_weather_forecast", {
47+
"latitude": stuttgart_lat,
48+
"longitude": stuttgart_lon,
49+
"days": 7
50+
})
51+
print(result.content[0].text)
52+
53+
asyncio.run(main())
54+
55+
# Made with Bob
File renamed without changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ fi
9494
project_guid=$(ibmcloud ce project get --name $ce_project_name --output json | jq -r '.guid')
9595

9696
print_msg "\nCreating the MCP Server as a code engine application"
97-
ibmcloud ce app create --name fastmcp --build-source ./server --build-strategy buildpacks --cpu 1 --memory 4G -p 8080 --wait-timeout 600 --min-scale 0 --scale-down-delay 120 --visibility public
97+
ibmcloud ce app create --name fastmcp --build-source ./server --build-strategy buildpacks --cpu 1 --memory 4G -p 8080 --wait-timeout 600 --min-scale 1 --scale-down-delay 120 --visibility public
9898

9999
while true; do
100100
ibmcloud ce app list
40.6 KB
Loading
321 KB
Loading
115 KB
Loading

0 commit comments

Comments
 (0)