diff --git a/ai/mcp_server_fastmcp/.gitignore b/ai/fastmcp-server/.gitignore similarity index 100% rename from ai/mcp_server_fastmcp/.gitignore rename to ai/fastmcp-server/.gitignore diff --git a/ai/mcp_server_fastmcp/README.md b/ai/fastmcp-server/README.md similarity index 52% rename from ai/mcp_server_fastmcp/README.md rename to ai/fastmcp-server/README.md index 614470e9..a08961ee 100644 --- a/ai/mcp_server_fastmcp/README.md +++ b/ai/fastmcp-server/README.md @@ -1,9 +1,9 @@ -FastMCP — Fast, tiny MCP server example -====================================== +FastMCP — Weather MCP Server +============================ Overview -------- -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. +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). ![](./images/architecture.png) @@ -32,40 +32,84 @@ Why Code Engine? - **Simple deployment**: Integrates with container registries and CI/CD pipelines. - **Managed endpoint**: Provides a secure http endpoint with a managed certificate. -A very tiny MCP Server ----------------------- +Weather MCP Server Features +--------------------------- + +The server provides three weather-related tools: + +1. **search_location**: Search for locations by name to get coordinates +2. **get_current_weather**: Get current weather conditions for specific coordinates +3. **get_weather_forecast**: Get weather forecast for 1-16 days The Python source code for the MCP server is located in [./server/main.py](./server/main.py): ```python from typing import Any from fastmcp import FastMCP -from art import text2art +import weather_api -mcp = FastMCP("My FastMCP Server on Code Engine") +mcp = FastMCP("Weather MCP Server on Code Engine") + +@mcp.tool +async def search_location(query: str) -> str: + """ + Search for a location by name to get coordinates for weather queries. + + Args: + query: The location name to search for (e.g., "London", "New York", "Tokyo") + + Returns: + A formatted string with matching locations and their coordinates + """ + try: + data = await weather_api.search_location(query) + return weather_api.format_location_results(data) + except Exception as e: + return f"Error searching for location: {str(e)}" @mcp.tool -def ascii_art(input: str) -> str: - """Take an arbitraty input and return it as an ASCII art banner""" - - if input == "Code Engine": - response = ". ___ __ ____ ____\n" - response += "./ __)/ \\( \\( __)\n" - response += "( (__( O )) D ( ) _)\n" - response += ".\\___)\\__/(____/(____)\n" - response += ".____ __ _ ___ __ __ _ ____\n" - response += "( __)( ( \\ / __)( )( ( \\( __)\n" - response += ".) _) / /( (_ \\ )( / / ) _)\n" - response += "(____)\\_)__) \\___/(__)\\_)__)(____)\n" - else: - response: str = text2art(input) - - return response +async def get_current_weather(latitude: float, longitude: float) -> str: + """ + Get the current weather conditions for a specific location. + + Args: + latitude: The latitude of the location (e.g., 51.5074 for London) + longitude: The longitude of the location (e.g., -0.1278 for London) + + Returns: + A formatted string with current weather information + """ + try: + data = await weather_api.get_current_weather(latitude, longitude) + return weather_api.format_current_weather(data) + except Exception as e: + return f"Error getting current weather: {str(e)}" + +@mcp.tool +async def get_weather_forecast(latitude: float, longitude: float, days: int = 7) -> str: + """ + Get the weather forecast for a specific location. + + Args: + latitude: The latitude of the location + longitude: The longitude of the location + days: Number of days to forecast (1-16, default: 7) + + Returns: + A formatted string with daily weather forecast + """ + try: + data = await weather_api.get_weather_forecast(latitude, longitude, days) + return weather_api.format_weather_forecast(data) + except Exception as e: + return f"Error getting weather forecast: {str(e)}" if __name__ == "__main__": mcp.run(transport="http", host="0.0.0.0", port=8080) ``` +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). + Deploying the server to Code Engine ---------------------------------- @@ -99,12 +143,13 @@ https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp Testing the deployed server with call_tool.sh --------------------------------------------- -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: +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: 1. Initializes an MCP session with the server 2. Lists all available tools -3. Calls the `ascii_art` tool with "Code Engine" as input -4. Displays the ASCII art output +3. Searches for Stuttgart location +4. Gets current weather for Stuttgart (coordinates: 48.7758, 9.1829) +5. Gets 7-day weather forecast for Stuttgart Run the script from the `mcp_server_fastmcp` directory: @@ -112,7 +157,7 @@ Run the script from the `mcp_server_fastmcp` directory: ./call_tool.sh ``` -The script will automatically connect to your deployed FastMCP application and execute a test call. You should see output similar to: +The script will automatically connect to your deployed FastMCP application and execute weather queries for Stuttgart. You should see output similar to: ``` FastMCP application is reachable under the following url: @@ -122,16 +167,32 @@ initialize session Session initialized: List tools -Call tool 'ascii_art' with input 'Code Engine' -. ___ __ ____ ____ -./ __)/ \( \( __) -.( (__( O )) D ( ) _) -.\___)\\__/(____/(____) -.____ __ _ ___ __ __ _ ____ -.( __)( ( \ / __)( )( ( \( __) -..) _) / /( (_ \ )( / / ) _) -.(____)\\_)__) \\___/(__)\\_)__)(____) +========================================== +WEATHER TOOLS DEMONSTRATION FOR STUTTGART +========================================== + +1. Search for 'Stuttgart' location +Stuttgart, Baden-Württemberg, Germany (lat: 48.7758, lon: 9.1829) + +2. Get current weather for Stuttgart +Current Weather: +Condition: Partly cloudy +Temperature: 15.2°C +Feels like: 14.8°C +Humidity: 65% +Wind Speed: 12.5 km/h +Precipitation: 0.0 mm + +3. Get 7-day weather forecast for Stuttgart +Weather Forecast: + +2026-03-20: + Condition: Partly cloudy + Temperature: 8.5°C - 16.2°C + Precipitation: 0.2 mm (probability: 20%) + Max Wind Speed: 18.5 km/h +... SUCCESS ``` @@ -147,7 +208,7 @@ Example `claude_desktop_config.json` entry that point to your deployed applicati ```json { "mcpServer": { - "ASCII Art FastMCP (Code Engine)": { + "Weather FastMCP (Code Engine)": { "command": "npx", "args": [ "mcp-remote", @@ -164,21 +225,20 @@ Save settings and restart Claude Desktop; the remote MCP server should appear as You can now chat with the MCP Server, e.g. -**_"Create ASCII art for: Hello, World!"_** +**_"Get the current weather and forecast of New York using the tool deployed in Code Engine :-)"_** -Claude will detect the tool and call the `ascii_art` function, responding with ASCII art output for your input text. +Claude will detect the appropriate weather tools and call them to provide current weather conditions or forecasts for the requested locations. ![](./images/claude_chat.png) -Note, the LLM even detected the simplicity of our MCP Server. - Building and using the Python client ----------------------------- -The `client` directory contains a small Python client to exercise the server. +The `client` directory contains a small Python client to exercise the weather server. 1. Create a virtual environment and install dependencies: ```bash +cd client python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt @@ -192,8 +252,13 @@ Start the client by replacing the application URL from above as the `MCP_SERVER_ MCP_SERVER_URL="https://fastmcp.26n4g2nfyw7s.eu-de.codeengine.appdomain.cloud/mcp" python client.py ``` +The client will demonstrate all three weather tools using Stuttgart as an example location: +- Search for Stuttgart location +- Get current weather for Stuttgart +- Get 7-day weather forecast for Stuttgart + 3. Inspect and adapt -- Open `client.py` to find example calls. The client is intentionally minimal so you can adapt it to your tooling or CI. +- 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. What's next? diff --git a/ai/mcp_server_fastmcp/call_tool.sh b/ai/fastmcp-server/call_tool.sh similarity index 60% rename from ai/mcp_server_fastmcp/call_tool.sh rename to ai/fastmcp-server/call_tool.sh index a1faff0f..215561ca 100755 --- a/ai/mcp_server_fastmcp/call_tool.sh +++ b/ai/fastmcp-server/call_tool.sh @@ -75,8 +75,16 @@ curl -s -X POST $url/mcp \ "params": {} }' | grep "data" | sed s/"data: "//g | jq . -print_msg "\nCall tool 'ascii_art' with input 'Code Engine'" -text=$(curl -s -X POST $url/mcp \ +# Stuttgart coordinates +STUTTGART_LAT=48.7758 +STUTTGART_LON=9.1829 + +print_msg "\n==========================================" +print_msg "WEATHER TOOLS DEMONSTRATION FOR STUTTGART" +print_msg "==========================================\n" + +print_msg "\n1. Search for 'Stuttgart' location" +curl -s -X POST $url/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Accept: text/event-stream" \ @@ -86,14 +94,51 @@ text=$(curl -s -X POST $url/mcp \ "id": 1, "method": "tools/call", "params": { - "name": "ascii_art", + "name": "search_location", "arguments": { - "input": "Code Engine" + "query": "Stuttgart" + } + } + }' | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text" + +print_msg "\n2. Get current weather for Stuttgart" +curl -s -X POST $url/mcp \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Accept: text/event-stream" \ + -H "Mcp-Session-Id: $session" \ + -d "{ + \"jsonrpc\": \"2.0\", + \"id\": 1, + \"method\": \"tools/call\", + \"params\": { + \"name\": \"get_current_weather\", + \"arguments\": { + \"latitude\": $STUTTGART_LAT, + \"longitude\": $STUTTGART_LON } } - }' | grep "data" | sed s/"data: "//g | jq ".result.content[0].text") + }" | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text" -echo -e $text +print_msg "\n3. Get 7-day weather forecast for Stuttgart" +curl -s -X POST $url/mcp \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Accept: text/event-stream" \ + -H "Mcp-Session-Id: $session" \ + -d "{ + \"jsonrpc\": \"2.0\", + \"id\": 1, + \"method\": \"tools/call\", + \"params\": { + \"name\": \"get_weather_forecast\", + \"arguments\": { + \"latitude\": $STUTTGART_LAT, + \"longitude\": $STUTTGART_LON, + \"days\": 7 + } + } + }" | grep "data" | sed s/"data: "//g | jq -r ".result.content[0].text" diff --git a/ai/fastmcp-server/client/client.py b/ai/fastmcp-server/client/client.py new file mode 100644 index 00000000..5825cb0f --- /dev/null +++ b/ai/fastmcp-server/client/client.py @@ -0,0 +1,55 @@ +import asyncio +import os +from fastmcp import Client, FastMCP + +mcp_server_url = os.getenv("MCP_SERVER_URL", default="http://localhost:8080/mcp") + +# HTTP server +client = Client(mcp_server_url) + +async def main(): + async with client: + # Basic server interaction + await client.ping() + + # List available operations + tools = await client.list_tools() + print("Available tools:", tools) + resources = await client.list_resources() + print("Available resources:", resources) + prompts = await client.list_prompts() + print("Available prompts:", prompts) + + # Stuttgart coordinates + stuttgart_lat = 48.7758 + stuttgart_lon = 9.1829 + + print("\n" + "="*50) + print("WEATHER TOOLS DEMONSTRATION") + print("="*50) + + # Search for Stuttgart location + print("\n1. Searching for 'Stuttgart'...") + result = await client.call_tool("search_location", {"query": "Stuttgart"}) + print(result.content[0].text) + + # Get current weather for Stuttgart + print("\n2. Getting current weather for Stuttgart...") + result = await client.call_tool("get_current_weather", { + "latitude": stuttgart_lat, + "longitude": stuttgart_lon + }) + print(result.content[0].text) + + # Get weather forecast for Stuttgart (7 days) + print("\n3. Getting 7-day weather forecast for Stuttgart...") + result = await client.call_tool("get_weather_forecast", { + "latitude": stuttgart_lat, + "longitude": stuttgart_lon, + "days": 7 + }) + print(result.content[0].text) + +asyncio.run(main()) + +# Made with Bob diff --git a/ai/mcp_server_fastmcp/client/requirements.txt b/ai/fastmcp-server/client/requirements.txt similarity index 100% rename from ai/mcp_server_fastmcp/client/requirements.txt rename to ai/fastmcp-server/client/requirements.txt diff --git a/ai/mcp_server_fastmcp/deploy.sh b/ai/fastmcp-server/deploy.sh similarity index 98% rename from ai/mcp_server_fastmcp/deploy.sh rename to ai/fastmcp-server/deploy.sh index f1db8133..d0092d11 100755 --- a/ai/mcp_server_fastmcp/deploy.sh +++ b/ai/fastmcp-server/deploy.sh @@ -94,7 +94,7 @@ fi project_guid=$(ibmcloud ce project get --name $ce_project_name --output json | jq -r '.guid') print_msg "\nCreating the MCP Server as a code engine application" -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 +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 while true; do ibmcloud ce app list diff --git a/ai/fastmcp-server/images/architecture.png b/ai/fastmcp-server/images/architecture.png new file mode 100644 index 00000000..52a4ca88 Binary files /dev/null and b/ai/fastmcp-server/images/architecture.png differ diff --git a/ai/fastmcp-server/images/claude_chat.png b/ai/fastmcp-server/images/claude_chat.png new file mode 100644 index 00000000..19dfadb0 Binary files /dev/null and b/ai/fastmcp-server/images/claude_chat.png differ diff --git a/ai/fastmcp-server/images/claude_settings.png b/ai/fastmcp-server/images/claude_settings.png new file mode 100644 index 00000000..3f69aec9 Binary files /dev/null and b/ai/fastmcp-server/images/claude_settings.png differ diff --git a/ai/mcp_server_fastmcp/server/Procfile b/ai/fastmcp-server/server/Procfile similarity index 100% rename from ai/mcp_server_fastmcp/server/Procfile rename to ai/fastmcp-server/server/Procfile diff --git a/ai/fastmcp-server/server/main.py b/ai/fastmcp-server/server/main.py new file mode 100644 index 00000000..640b99d5 --- /dev/null +++ b/ai/fastmcp-server/server/main.py @@ -0,0 +1,79 @@ +from typing import Any +from fastmcp import FastMCP +import weather_api + +mcp = FastMCP(name="Weather MCP Server on Code Engine", instructions=""" +OpenWeatherMap MCP Server + + This server provides comprehensive and live weather data from OpenWeatherMap API. + + Available tools: + - get_current_weather: Current weather for any location + - get_forecast: 5-day weather forecast + - search_location: Find locations by name +""") + + +@mcp.tool +async def search_location(query: str) -> str: + """ + Search for a location by name to get coordinates for weather queries. + + Args: + query: The location name to search for (e.g., "London", "New York", "Tokyo") + + Returns: + A formatted string with matching locations and their coordinates + """ + try: + data = await weather_api.search_location(query) + return weather_api.format_location_results(data) + except Exception as e: + return f"Error searching for location: {str(e)}" + + +@mcp.tool +async def get_current_weather(latitude: float, longitude: float) -> str: + """ + Get the current weather conditions for a specific location. + + Args: + latitude: The latitude of the location (e.g., 51.5074 for London) + longitude: The longitude of the location (e.g., -0.1278 for London) + + Returns: + A formatted string with current weather information including temperature, + humidity, wind speed, and precipitation + """ + try: + data = await weather_api.get_current_weather(latitude, longitude) + return weather_api.format_current_weather(data) + except Exception as e: + return f"Error getting current weather: {str(e)}" + + +@mcp.tool +async def get_weather_forecast(latitude: float, longitude: float, days: int = 7) -> str: + """ + Get the weather forecast for a specific location. + + Args: + latitude: The latitude of the location (e.g., 51.5074 for London) + longitude: The longitude of the location (e.g., -0.1278 for London) + days: Number of days to forecast (1-16, default: 7) + + Returns: + A formatted string with daily weather forecast including temperature ranges, + precipitation, and wind speed + """ + try: + data = await weather_api.get_weather_forecast(latitude, longitude, days) + return weather_api.format_weather_forecast(data) + except Exception as e: + return f"Error getting weather forecast: {str(e)}" + + +if __name__ == "__main__": + mcp.run(transport="http", host="0.0.0.0", port=8080) + +# Made with Bob diff --git a/ai/mcp_server_fastmcp/server/requirements.txt b/ai/fastmcp-server/server/requirements.txt similarity index 61% rename from ai/mcp_server_fastmcp/server/requirements.txt rename to ai/fastmcp-server/server/requirements.txt index e7aa0968..6569341f 100644 --- a/ai/mcp_server_fastmcp/server/requirements.txt +++ b/ai/fastmcp-server/server/requirements.txt @@ -1,2 +1,2 @@ fastmcp -art \ No newline at end of file +httpx \ No newline at end of file diff --git a/ai/fastmcp-server/server/weather_api.py b/ai/fastmcp-server/server/weather_api.py new file mode 100644 index 00000000..8c7d81d8 --- /dev/null +++ b/ai/fastmcp-server/server/weather_api.py @@ -0,0 +1,234 @@ +"""Weather API functions using Open-Meteo API""" +import httpx +from typing import Optional + + +async def search_location(query: str) -> dict: + """ + Search for a location using the Open-Meteo Geocoding API. + + Args: + query: Location name to search for + + Returns: + Dictionary containing location search results + """ + async with httpx.AsyncClient() as client: + response = await client.get( + "https://geocoding-api.open-meteo.com/v1/search", + params={"name": query, "count": 5, "language": "en", "format": "json"} + ) + response.raise_for_status() + return response.json() + + +async def get_current_weather(latitude: float, longitude: float) -> dict: + """ + Get current weather for a location using Open-Meteo API. + + Args: + latitude: Latitude of the location + longitude: Longitude of the location + + Returns: + Dictionary containing current weather data + """ + async with httpx.AsyncClient() as client: + response = await client.get( + "https://api.open-meteo.com/v1/forecast", + params={ + "latitude": latitude, + "longitude": longitude, + "current": "temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m", + "temperature_unit": "celsius", + "wind_speed_unit": "kmh", + "precipitation_unit": "mm" + } + ) + response.raise_for_status() + return response.json() + + +async def get_weather_forecast(latitude: float, longitude: float, days: int = 7) -> dict: + """ + Get weather forecast for a location using Open-Meteo API. + + Args: + latitude: Latitude of the location + longitude: Longitude of the location + days: Number of days to forecast (default: 7, max: 16) + + Returns: + Dictionary containing weather forecast data + """ + # Ensure days is within valid range + days = min(max(1, days), 16) + + async with httpx.AsyncClient() as client: + response = await client.get( + "https://api.open-meteo.com/v1/forecast", + params={ + "latitude": latitude, + "longitude": longitude, + "daily": "weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,wind_speed_10m_max", + "temperature_unit": "celsius", + "wind_speed_unit": "kmh", + "precipitation_unit": "mm", + "forecast_days": days + } + ) + response.raise_for_status() + return response.json() + + +def format_location_results(data: dict) -> str: + """ + Format location search results into a readable string. + + Args: + data: Location search results from the API + + Returns: + Formatted string with location information + """ + if "results" not in data or not data["results"]: + return "No locations found." + + results = [] + for location in data["results"]: + name = location.get("name", "Unknown") + country = location.get("country", "Unknown") + admin1 = location.get("admin1", "") + lat = location.get("latitude", 0) + lon = location.get("longitude", 0) + + location_str = f"{name}" + if admin1: + location_str += f", {admin1}" + location_str += f", {country}" + location_str += f" (lat: {lat:.4f}, lon: {lon:.4f})" + + results.append(location_str) + + return "\n".join(results) + + +def format_current_weather(data: dict) -> str: + """ + Format current weather data into a readable string. + + Args: + data: Current weather data from the API + + Returns: + Formatted string with current weather information + """ + if "current" not in data: + return "No current weather data available." + + current = data["current"] + + weather_codes = { + 0: "Clear sky", + 1: "Mainly clear", + 2: "Partly cloudy", + 3: "Overcast", + 45: "Foggy", + 48: "Depositing rime fog", + 51: "Light drizzle", + 53: "Moderate drizzle", + 55: "Dense drizzle", + 61: "Slight rain", + 63: "Moderate rain", + 65: "Heavy rain", + 71: "Slight snow", + 73: "Moderate snow", + 75: "Heavy snow", + 77: "Snow grains", + 80: "Slight rain showers", + 81: "Moderate rain showers", + 82: "Violent rain showers", + 85: "Slight snow showers", + 86: "Heavy snow showers", + 95: "Thunderstorm", + 96: "Thunderstorm with slight hail", + 99: "Thunderstorm with heavy hail" + } + + weather_code = current.get("weather_code", 0) + weather_desc = weather_codes.get(weather_code, "Unknown") + + result = f"Current Weather:\n" + result += f"Condition: {weather_desc}\n" + result += f"Temperature: {current.get('temperature_2m', 'N/A')}°C\n" + result += f"Feels like: {current.get('apparent_temperature', 'N/A')}°C\n" + result += f"Humidity: {current.get('relative_humidity_2m', 'N/A')}%\n" + result += f"Wind Speed: {current.get('wind_speed_10m', 'N/A')} km/h\n" + result += f"Precipitation: {current.get('precipitation', 'N/A')} mm\n" + + return result + + +def format_weather_forecast(data: dict) -> str: + """ + Format weather forecast data into a readable string. + + Args: + data: Weather forecast data from the API + + Returns: + Formatted string with weather forecast information + """ + if "daily" not in data: + return "No forecast data available." + + daily = data["daily"] + dates = daily.get("time", []) + + weather_codes = { + 0: "Clear sky", + 1: "Mainly clear", + 2: "Partly cloudy", + 3: "Overcast", + 45: "Foggy", + 48: "Depositing rime fog", + 51: "Light drizzle", + 53: "Moderate drizzle", + 55: "Dense drizzle", + 61: "Slight rain", + 63: "Moderate rain", + 65: "Heavy rain", + 71: "Slight snow", + 73: "Moderate snow", + 75: "Heavy snow", + 77: "Snow grains", + 80: "Slight rain showers", + 81: "Moderate rain showers", + 82: "Violent rain showers", + 85: "Slight snow showers", + 86: "Heavy snow showers", + 95: "Thunderstorm", + 96: "Thunderstorm with slight hail", + 99: "Thunderstorm with heavy hail" + } + + result = "Weather Forecast:\n\n" + + for i, date in enumerate(dates): + weather_code = daily.get("weather_code", [])[i] if i < len(daily.get("weather_code", [])) else 0 + weather_desc = weather_codes.get(weather_code, "Unknown") + temp_max = daily.get("temperature_2m_max", [])[i] if i < len(daily.get("temperature_2m_max", [])) else "N/A" + temp_min = daily.get("temperature_2m_min", [])[i] if i < len(daily.get("temperature_2m_min", [])) else "N/A" + precip = daily.get("precipitation_sum", [])[i] if i < len(daily.get("precipitation_sum", [])) else "N/A" + precip_prob = daily.get("precipitation_probability_max", [])[i] if i < len(daily.get("precipitation_probability_max", [])) else "N/A" + wind = daily.get("wind_speed_10m_max", [])[i] if i < len(daily.get("wind_speed_10m_max", [])) else "N/A" + + result += f"{date}:\n" + result += f" Condition: {weather_desc}\n" + result += f" Temperature: {temp_min}°C - {temp_max}°C\n" + result += f" Precipitation: {precip} mm (probability: {precip_prob}%)\n" + result += f" Max Wind Speed: {wind} km/h\n\n" + + return result + +# Made with Bob diff --git a/ai/mcp_server_fastmcp/client/client.py b/ai/mcp_server_fastmcp/client/client.py deleted file mode 100644 index 5eeca460..00000000 --- a/ai/mcp_server_fastmcp/client/client.py +++ /dev/null @@ -1,27 +0,0 @@ -import asyncio -import os -from fastmcp import Client, FastMCP - -mcp_server_url = os.getenv("MCP_SERVER_URL", default="http://localhost:8080/mcp") - -# HTTP server -client = Client(mcp_server_url) - -async def main(): - async with client: - # Basic server interaction - await client.ping() - - # List available operations - tools = await client.list_tools() - print("Available tools:", tools) - resources = await client.list_resources() - print("Available resources:", resources) - prompts = await client.list_prompts() - print("Available prompts:", prompts) - - # Execute operations - result = await client.call_tool("ascii_art", {"input": "Code Engine"}) - print(result.content[0].text) - -asyncio.run(main()) \ No newline at end of file diff --git a/ai/mcp_server_fastmcp/images/architecture.png b/ai/mcp_server_fastmcp/images/architecture.png deleted file mode 100644 index 4e71ed6d..00000000 Binary files a/ai/mcp_server_fastmcp/images/architecture.png and /dev/null differ diff --git a/ai/mcp_server_fastmcp/images/claude_chat.png b/ai/mcp_server_fastmcp/images/claude_chat.png deleted file mode 100644 index b8f61556..00000000 Binary files a/ai/mcp_server_fastmcp/images/claude_chat.png and /dev/null differ diff --git a/ai/mcp_server_fastmcp/images/claude_settings.png b/ai/mcp_server_fastmcp/images/claude_settings.png deleted file mode 100644 index 583c8d4e..00000000 Binary files a/ai/mcp_server_fastmcp/images/claude_settings.png and /dev/null differ diff --git a/ai/mcp_server_fastmcp/server/main.py b/ai/mcp_server_fastmcp/server/main.py deleted file mode 100644 index ec6a4493..00000000 --- a/ai/mcp_server_fastmcp/server/main.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any -from fastmcp import FastMCP -from art import text2art - -mcp = FastMCP("My FastMCP Server on Code Engine") - -@mcp.tool -def ascii_art(input: str) -> str: - """Take an arbitraty input and return it as an ASCII art banner""" - - if input == "Code Engine": - response = ". ___ __ ____ ____\n" - response += "./ __)/ \\( \\( __)\n" - response += "( (__( O )) D ( ) _)\n" - response += ".\\___)\\__/(____/(____)\n" - response += ".____ __ _ ___ __ __ _ ____\n" - response += "( __)( ( \\ / __)( )( ( \\( __)\n" - response += ".) _) / /( (_ \\ )( / / ) _)\n" - response += "(____)\\_)__) \\___/(__)\\_)__)(____)\n" - else: - response: str = text2art(input) - - return response - -if __name__ == "__main__": - mcp.run(transport="http", host="0.0.0.0", port=8080) \ No newline at end of file