Skip to content

Commit feb2811

Browse files
committed
Merge branch 'main' of github.com:IBM/CodeEngine into metric-collector-v2
2 parents 50ad26b + f123835 commit feb2811

62 files changed

Lines changed: 6540 additions & 313 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ai/common.sh

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/bin/bash
2+
3+
# ==============================
4+
# COMMON FUNCTIONS
5+
# ==============================
6+
7+
RED="\033[31m"
8+
BLUE="\033[94m"
9+
GREEN="\033[32m"
10+
ENDCOLOR="\033[0m"
11+
12+
function print_error {
13+
echo -e "${RED}\n==========================================${ENDCOLOR}"
14+
echo -e "${RED} FAILED${ENDCOLOR}"
15+
echo -e "${RED}==========================================\n${ENDCOLOR}"
16+
echo -e "${RED}$1${ENDCOLOR}"
17+
echo -e ""
18+
}
19+
function print_msg {
20+
echo -e "${BLUE}$1${ENDCOLOR}"
21+
}
22+
function print_success {
23+
echo -e "${GREEN}$1${ENDCOLOR}"
24+
}
25+
26+
# Helper function to check whether prerequisites are installed
27+
function check_prerequisites {
28+
# Ensure that jq tool is installed
29+
if ! command -v jq &>/dev/null; then
30+
print_error "'jq' tool is not installed"
31+
exit 1
32+
fi
33+
}
34+
35+
# ==============================
36+
# COMMON IBMCLOUD HELPERS
37+
# ==============================
38+
39+
# helper function to check whether IBM Cloud CLI plugins should get updated, or not
40+
function ensure_plugin_is_up_to_date() {
41+
echo "Checking $1 ..."
42+
# check whether plugin is installed
43+
if ! ibmcloud plugin show $1 -q >/dev/null; then
44+
# install it
45+
ibmcloud plugin install $1 -f --quiet
46+
else
47+
# check whether there is an update available
48+
ibmcloud plugin update $1 -f --quiet
49+
fi
50+
}
51+
52+
function target_region {
53+
print_msg "\nTargetting IBM Cloud region '$1' ..."
54+
current_region=$(ibmcloud target --output JSON |jq -r '.region|.name')
55+
if [[ "$current_region" != "$1" ]]; then
56+
ibmcloud target -r $1 --quiet
57+
fi
58+
}
59+
60+
function target_resource_group {
61+
print_msg "\nTargetting resource group '$1' ..."
62+
current_resource_group_guid=$(ibmcloud target --output JSON |jq -r '.resource_group|.guid')
63+
new_resource_group_guid=$(ibmcloud resource group $1 -output json|jq -r '.[0].id')
64+
if [[ "$current_resource_group_guid" != "$new_resource_group_guid" ]]; then
65+
ibmcloud target -g $1 --quiet
66+
fi
67+
echo "Done"
68+
}
69+
70+
function does_instance_exist {
71+
(( $(ibmcloud resource search "service_name:\"$1\" AND name:\"$2\"" --output JSON|jq -r '.items|length') > 0 ))
72+
}
73+
74+
function does_serviceid_exist {
75+
(( $(ibmcloud resource search "type:serviceid AND name:\"$1\"" --output JSON|jq -r '.items|length') > 0 ))
76+
}
77+
78+
function has_bucket_name_with_prefix {
79+
buckets=$(ibmcloud cos buckets -output json)
80+
COS_BUCKET_NAME=""
81+
if [[ "$(echo "${buckets}" | jq -r '.Buckets')" != "null" ]]; then
82+
for bucket in $(echo "${buckets}" | jq -r '.Buckets|.[] | @base64'); do
83+
_jq() {
84+
echo ${bucket} | base64 --decode | jq -r ${1}
85+
}
86+
bucket_name=$(_jq '.Name')
87+
if [[ "$bucket_name" =~ ^$1-* ]]; then
88+
COS_BUCKET_NAME=$bucket_name
89+
fi
90+
done
91+
fi
92+
echo $COS_BUCKET_NAME
93+
}
94+
95+
96+
function abortScript() {
97+
if [[ "${CLEANUP_ON_ERROR}" == true ]]; then
98+
clean
99+
else
100+
print_msg "\nSkipping deletion of the created IBM Cloud resources. Please be aware that the created resources will occur costs in your account."
101+
echo "$ ibmcloud resource service-instances --type all -g $resource_group_name --location $REGION"
102+
ibmcloud resource service-instances --type all -g $resource_group_name --location $REGION
103+
fi
104+
exit 1
105+
}

ai/fastmcp-server/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/.venv

ai/fastmcp-server/README.md

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
FastMCP — Weather MCP Server
2+
============================
3+
4+
Overview
5+
--------
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).
7+
8+
![](./images/architecture.png)
9+
10+
About MCP and FastMCP
11+
---------------------
12+
13+
MCP (Model Context Protocol) is a lightweight, transport-agnostic convention for exchanging model prompts, context, and responses between clients and model-serving services. It emphasizes:
14+
15+
- **Transport flexibility**: works over HTTP, SSE, WebSocket, stdio and other streamable transports.
16+
- **Streaming-first behavior**: supports incremental/streaming responses for low-latency UX.
17+
- **Simple JSON semantics**: easy to implement and interoperate between services.
18+
19+
**[FastMCP](https://gofastmcp.com/getting-started/welcome) is the standard framework for building MCP applications.**
20+
21+
The [Direct Http Server](https://gofastmcp.com/deployment/http#direct-http-server) example provides a minimal reference implementation meant for experimentation and quick deployments. It focuses on a very small API surface and fast startup so you can iterate locally or run tiny instances in cloud platforms like Code Engine.
22+
23+
24+
Why Code Engine?
25+
-----------------
26+
27+
[IBM Cloud Code Engine](https://www.ibm.com/products/code-engine) is a great fit for containerized MCP Servers because it provides:
28+
29+
- **Serverless containers**: Deploy container images without managing infrastructure.
30+
- **Automatic scaling**: Scale to zero when idle and scale up on demand.
31+
- **Pay-per-use pricing**: Cost-efficient for intermittent workloads common to agents.
32+
- **Simple deployment**: Integrates with container registries and CI/CD pipelines.
33+
- **Managed endpoint**: Provides a secure http endpoint with a managed certificate.
34+
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
43+
44+
The Python source code for the MCP server is located in [./server/main.py](./server/main.py):
45+
46+
```python
47+
from typing import Any
48+
from fastmcp import FastMCP
49+
import weather_api
50+
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)}"
69+
70+
@mcp.tool
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)}"
106+
107+
if __name__ == "__main__":
108+
mcp.run(transport="http", host="0.0.0.0", port=8080)
109+
```
110+
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+
113+
Deploying the server to Code Engine
114+
----------------------------------
115+
116+
**Prerequisites**
117+
Create an IBM Cloud account and [login into your IBM Cloud account using the IBM Cloud CLI](https://cloud.ibm.com/docs/codeengine?topic=codeengine-install-cli).
118+
119+
**Deploy**
120+
121+
1. Authenticate and login to IBM Cloud:
122+
123+
```bash
124+
ibmcloud login --sso
125+
ibmcloud login --apikey "$IBMCLOUD_APIKEY" -r us-south
126+
127+
```
128+
129+
2. Run the included deploy script from this folder. The script creates a new Code Engine project in the specified region and automates build/push/deploy steps to create a new application in Code Engine.
130+
131+
```bash
132+
NAME_PREFIX=ce-fastmcp REGION=eu-de ./deploy.sh
133+
```
134+
135+
3. The deploy script will print the URL under which the MCP Server is publicly accessible
136+
137+
```
138+
FastMCP application is reachable under the following url:
139+
https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp
140+
```
141+
142+
🚀 The example was successful and you can now use the MCP server in your chat application 🚀
143+
144+
Testing the deployed server with call_tool.sh
145+
---------------------------------------------
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:
147+
148+
1. Initializes an MCP session with the server
149+
2. Lists all available tools
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
153+
154+
Run the script from the `mcp_server_fastmcp` directory:
155+
156+
```bash
157+
./call_tool.sh
158+
```
159+
160+
The script will automatically connect to your deployed FastMCP application and execute weather queries for Stuttgart. You should see output similar to:
161+
162+
```
163+
FastMCP application is reachable under the following url:
164+
https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp
165+
166+
initialize session
167+
Session initialized: <session-id>
168+
169+
List tools
170+
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+
...
196+
197+
SUCCESS
198+
```
199+
200+
201+
Using this example with Claude Desktop
202+
-------------------------------------
203+
Claude Desktop can connect to local or remote MCP servers by registering them in its `claude_desktop_config.json` (Claude -> Settings -> Developer -> Edit Config).
204+
205+
206+
Example `claude_desktop_config.json` entry that point to your deployed application URL:
207+
208+
```json
209+
{
210+
"mcpServer": {
211+
"Weather FastMCP (Code Engine)": {
212+
"command": "npx",
213+
"args": [
214+
"mcp-remote",
215+
"https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp"
216+
]
217+
}
218+
}
219+
}
220+
```
221+
222+
Save settings and restart Claude Desktop; the remote MCP server should appear as a selectable tool in Claude Desktop.
223+
224+
![](./images/claude_settings.png)
225+
226+
You can now chat with the MCP Server, e.g.
227+
228+
**_"Get the current weather and forecast of New York using the tool deployed in Code Engine :-)"_**
229+
230+
Claude will detect the appropriate weather tools and call them to provide current weather conditions or forecasts for the requested locations.
231+
232+
![](./images/claude_chat.png)
233+
234+
Building and using the Python client
235+
-----------------------------
236+
The `client` directory contains a small Python client to exercise the weather server.
237+
238+
1. Create a virtual environment and install dependencies:
239+
240+
```bash
241+
cd client
242+
python3 -m venv .venv
243+
source .venv/bin/activate
244+
pip install -r requirements.txt
245+
```
246+
247+
2. Run the client
248+
249+
Start the client by replacing the application URL from above as the `MCP_SERVER_URL` environment variable, e.g.
250+
251+
```bash
252+
MCP_SERVER_URL="https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp" python client.py
253+
```
254+
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+
260+
3. Inspect and adapt
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.
262+
263+
264+
What's next?
265+
------------
266+
267+
You now have a very simple reference architecture to deploy any MCP server of your choice.

0 commit comments

Comments
 (0)