Model Context Protocol Service - Standalone API service providing Weather, Time, and Owner Info endpoints for ZORA AI chatbot.
MCP Service is a FastAPI-based microservice that provides specialized tools for the ZORA AI chatbot through RESTful APIs. It uses Open-Meteo (completely FREE) for weather data and requires no API keys.
- ✅ 100% Free - Uses Open-Meteo (no API key required)
- ✅ RESTful APIs - Easy to integrate
- ✅ Real-time Weather - 30+ Vietnamese cities
- ✅ World Time - 15+ countries/timezones
- ✅ Auto-docs - Swagger UI included
- ✅ Fast & Reliable - Average response time < 200ms
http://localhost:8001
Get current weather for Vietnamese cities.
Endpoint:
GET /api/weather?city={city_name}
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| city | string | Yes | City name (e.g., Hanoi, Ho Chi Minh, Da Nang) |
Example Request:
curl "http://localhost:8001/api/weather?city=Hanoi"Example Response:
{
"success": true,
"city": "Hanoi",
"temperature": 28.5,
"description": "Trời quang đãng",
"humidity": 65,
"wind_speed": 12.5,
"weather_code": 0,
"emoji": "☀️"
}Supported Cities (30+):
Hà Nội, TP HCM (Sài Gòn), Đà Nẵng, Huế, Nha Trang,
Cần Thơ, Hải Phòng, Vũng Tàu, Biên Hòa, Đà Lạt,
Quy Nhơn, Hạ Long, Vinh, Buôn Ma Thuột, Phan Thiết, ...
Weather Codes:
| Code | Description | Emoji |
|---|---|---|
| 0 | Trời quang đãng | ☀️ |
| 1-2 | Có mây một phần | 🌤️ |
| 3 | U ám | ☁️ |
| 45-48 | Có sương mù | 🌫️ |
| 51-67 | Mưa | 🌧️ |
| 71-77 | Tuyết | ❄️ |
| 80-82 | Mưa rào | 🌧️ |
| 95-99 | Giông bão | ⛈️ |
Get current time for any country.
Endpoint:
GET /api/time?country={country_name}
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| country | string | Yes | Country name (e.g., Vietnam, USA, Japan) |
Example Request:
curl "http://localhost:8001/api/time?country=Vietnam"Example Response:
{
"success": true,
"country": "Vietnam",
"timezone": "Asia/Ho_Chi_Minh",
"current_time": "14:30:45",
"date": "15/11/2025",
"timestamp": "2025-11-15T14:30:45+07:00"
}Supported Countries (15+):
Việt Nam, Mỹ (USA), Nhật Bản (Japan), Anh (UK),
Pháp (France), Đức (Germany), Singapore, Thái Lan (Thailand),
Hàn Quốc (South Korea), Úc (Australia), Canada,
Ấn Độ (India), Indonesia, Malaysia, Philippines
Get information about ZORA AI's creator.
Endpoint:
GET /api/owner
Parameters: None
Example Request:
curl "http://localhost:8001/api/owner"Example Response:
{
"success": true,
"name": "Nguyễn Trung Thành (Jimmy Nguyen)",
"phone": "0432047700",
"email": "ng.trungthanh04@gmail.com",
"role": "AI Developer & Software Engineer",
"bio": "Tôi là Nguyễn Trung Thành, người sáng tạo ra ZORA AI...",
"skills": [
"Python",
"FastAPI",
"LangChain",
"Machine Learning",
"Natural Language Processing",
"RAG Systems",
"PostgreSQL",
"Docker",
"MCP Protocol"
]
}Get list of available tools with keywords for detection.
Endpoint:
GET /api/tools
Parameters: None
Example Request:
curl "http://localhost:8001/api/tools"Example Response:
{
"tools": [
{
"name": "get_weather",
"endpoint": "/api/weather",
"method": "GET",
"description": "Lấy thông tin thời tiết hiện tại của một thành phố ở Việt Nam",
"parameters": {
"city": {
"type": "string",
"required": true,
"description": "Tên thành phố (vd: Hanoi, Ho Chi Minh, Da Nang)"
}
},
"keywords": [
"thời tiết", "nhiệt độ", "nóng", "lạnh", "mưa", "nắng",
"weather", "temperature", "hot", "cold", "rain", "sunny"
],
"example": "GET /api/weather?city=Hanoi"
},
// ... more tools
],
"cities": ["Hanoi", "Ho Chi Minh City", "Da Nang", ...],
"countries": ["vietnam", "usa", "japan", ...]
}Check service status.
Endpoint:
GET /health
Example Response:
{
"status": "healthy",
"timestamp": "2025-11-15T14:30:45.123456"
}- Clone or create the project:
mkdir mcp-service
cd mcp-service- Install dependencies:
pip install fastapi uvicorn httpx pytz-
Create
main.pywith the MCP Service code -
Run the service:
python main.pyOr using uvicorn directly:
uvicorn main:app --host 0.0.0.0 --port 8001 --reload- Access Swagger UI:
http://localhost:8001/docs
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
EXPOSE 8001
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]Build and run:
docker build -t zora-mcp-service .
docker run -p 8001:8001 zora-mcp-serviceWeather API:
├── Average latency: 180ms
├── Success rate: 99.9%
├── Rate limit: 10,000+ calls/day
└── Uptime: 99.9%+
Time API:
├── Average latency: <5ms
├── Success rate: 100%
├── Rate limit: Unlimited
└── Uptime: 100%
Owner Info API:
├── Average latency: <5ms
├── Success rate: 100%
├── Rate limit: Unlimited
└── Uptime: 100%
Create .env file (optional):
# Service configuration
SERVICE_HOST=0.0.0.0
SERVICE_PORT=8001
# CORS settings (if needed)
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8000Edit main.py to customize:
Add new city:
VIETNAM_CITIES = {
"your_city": ("Your City Name", latitude, longitude),
# Example:
"phu quoc": ("Phu Quoc", 10.2291, 103.9673),
}Add new country:
COUNTRY_TIMEZONES = {
"your_country": "Continent/City",
# Example:
"brazil": "America/Sao_Paulo",
}Test Weather:
curl "http://localhost:8001/api/weather?city=Hanoi"Test Time:
curl "http://localhost:8001/api/time?country=Vietnam"Test Owner Info:
curl "http://localhost:8001/api/owner"Create test_mcp_service.py:
import httpx
import pytest
BASE_URL = "http://localhost:8001"
@pytest.mark.asyncio
async def test_weather_api():
async with httpx.AsyncClient() as client:
response = await client.get(f"{BASE_URL}/api/weather?city=Hanoi")
assert response.status_code == 200
data = response.json()
assert data["success"] == True
assert "temperature" in data
@pytest.mark.asyncio
async def test_time_api():
async with httpx.AsyncClient() as client:
response = await client.get(f"{BASE_URL}/api/time?country=Vietnam")
assert response.status_code == 200
data = response.json()
assert data["success"] == True
assert "current_time" in data
@pytest.mark.asyncio
async def test_owner_api():
async with httpx.AsyncClient() as client:
response = await client.get(f"{BASE_URL}/api/owner")
assert response.status_code == 200
data = response.json()
assert data["success"] == True
assert "name" in dataRun tests:
pytest test_mcp_service.py -v- Rate Limiting (add if needed):
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
@app.get("/api/weather")
@limiter.limit("100/minute")
async def get_weather(request: Request, city: str):
# ...- API Key Authentication (optional):
from fastapi import Header, HTTPException
async def verify_api_key(x_api_key: str = Header(...)):
if x_api_key != "your-secret-key":
raise HTTPException(status_code=401, detail="Invalid API key")- CORS Configuration:
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-frontend.com"], # Specific domains only
allow_credentials=True,
allow_methods=["GET"],
allow_headers=["*"],
)Uptime monitoring:
*/5 * * * * curl -f http://localhost:8001/health || alertPrometheus metrics (add if needed):
from prometheus_fastapi_instrumentator import Instrumentator
Instrumentator().instrument(app).expose(app)import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
@app.get("/api/weather")
async def get_weather(city: str):
logger.info(f"Weather request for city: {city}")
# ...1. Service won't start:
# Check if port 8001 is in use
lsof -i :8001
# Kill process if needed
kill -9 <PID>2. Weather API returns 500:
- Check internet connection
- Verify Open-Meteo API status: https://open-meteo.com
- Check logs for detailed error
3. Time API returns wrong timezone:
- Verify country name spelling
- Check
COUNTRY_TIMEZONESmapping - Use exact country names from supported list
4. CORS errors:
- Update
allow_originsin CORS middleware - Check browser console for detailed error
import httpx
async def get_weather(city: str):
async with httpx.AsyncClient() as client:
response = await client.get(
"http://localhost:8001/api/weather",
params={"city": city}
)
return response.json()
# Usage
weather = await get_weather("Hanoi")
print(f"Temperature: {weather['temperature']}°C")async function getWeather(city) {
const response = await fetch(
`http://localhost:8001/api/weather?city=${city}`
);
return await response.json();
}
// Usage
const weather = await getWeather('Hanoi');
console.log(`Temperature: ${weather.temperature}°C`);# Weather
curl "http://localhost:8001/api/weather?city=Hanoi"
# Time
curl "http://localhost:8001/api/time?country=Vietnam"
# Owner Info
curl "http://localhost:8001/api/owner"# In your chatbot service
if "weather" in user_question:
city = extract_city(user_question)
weather = await mcp_client.get_weather(city)
return format_weather_response(weather)# Detect intent and call appropriate API
intents = agent_detector.detect(user_question)
for intent in intents:
if intent.type == "weather":
response = await mcp_client.get_weather(intent.params["city"])# Convert speech to text, call MCP, convert response to speech
text = speech_to_text(audio)
if "thời tiết" in text:
weather = await mcp_client.get_weather(extract_city(text))
audio_response = text_to_speech(format_weather(weather))Want to add more features?
Ideas:
- Currency exchange rates
- News headlines
- Stock prices
- Translation service
- Wikipedia search
- Calculator/math solver
How to contribute:
- Fork the repository
- Create feature branch
- Add your endpoint
- Test thoroughly
- Submit pull request
Creator: Nguyễn Trung Thành (Jimmy Nguyen)
- 📧 Email: ng.trungthanh04@gmail.com
- 📱 Phone: 0432047700
Service Issues:
- Check
/healthendpoint - Review logs
- Verify Open-Meteo status
MIT License - Free to use in your projects!
- ✨ Initial release
- ✅ Weather API (Open-Meteo)
- ✅ Time API
- ✅ Owner Info API
- ✅ Auto-documentation (Swagger)
- ✅ Health check endpoint
- ✅ 30+ Vietnamese cities
- ✅ 15+ countries
Made with ❤️ by Nguyễn Trung Thành
Powered by Open-Meteo 🌤️ (Free & Open Source)