Skip to main content
Glama

Context Engineering MCP Platform

main.py11.8 kB
import logging import os from typing import Dict, List, Optional, Any from dotenv import load_dotenv from fastapi import FastAPI, HTTPException, Query from pydantic import BaseModel # Load environment variables from .env file load_dotenv() # --- Configuration and Logging --- APP_NAME = os.getenv("APP_NAME", "MCP AI Guides Server") APP_VERSION = os.getenv("APP_VERSION", "1.0.0") LOG_LEVEL = os.getenv("LOG_LEVEL", "info").upper() # Configure logging logging.basicConfig( level=getattr(logging, LOG_LEVEL), format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) # --- Data Source (Hardcoded for demonstration) --- AI_GUIDES_DATA: List[Dict[str, str | List[str]]] = [ { "title": "OpenAI: GPT Best Practices", "publisher": "OpenAI", "description": "Comprehensive guide on best practices for prompting and using GPT models effectively.", "topics": ["prompt engineering", "LLM usage", "AI best practices"], "download_url": "https://example.com/openai-gpt-best-practices.pdf" }, { "title": "Google: Introduction to Generative AI", "publisher": "Google", "description": "An introductory course to generative AI concepts and applications.", "topics": ["generative AI", "AI fundamentals", "machine learning"], "download_url": "https://example.com/google-intro-gen-ai.pdf" }, { "title": "Anthropic: Constitutional AI", "publisher": "Anthropic", "description": "Exploration of Constitutional AI for building safe and helpful AI systems.", "topics": ["AI safety", "AI ethics", "constitutional AI"], "download_url": "https://example.com/anthropic-constitutional-ai.pdf" }, { "title": "OpenAI: AI Agent Construction Guidelines", "publisher": "OpenAI", "description": "A detailed guide on constructing robust and intelligent AI agents.", "topics": ["AI agents", "agent architecture", "AI development"], "download_url": "https://example.com/openai-ai-agents.pdf" }, { "title": "Google: Enterprise AI Deployment Strategies", "publisher": "Google", "description": "Strategies and best practices for deploying AI solutions at enterprise scale.", "topics": ["enterprise AI", "AI deployment", "MLOps"], "download_url": "https://example.com/google-enterprise-ai.pdf" } ] # --- Request/Response Models --- class GuideComparisonRequest(BaseModel): guide_titles: List[str] class GeminiSearchRequest(BaseModel): query: str use_grounding: bool = True # --- FastAPI Application Instance --- app = FastAPI( title=APP_NAME, version=APP_VERSION, description="A centralized repository and search interface for a curated collection of free AI-related guides from OpenAI, Google, and Anthropic. Enhanced with Gemini AI for intelligent search and analysis." ) # --- Helper Functions --- def _find_guide_by_title(title: str) -> Optional[Dict[str, str | List[str]]]: """Finds an AI guide by its exact title (case-insensitive for comparison).""" for guide in AI_GUIDES_DATA: if guide["title"].lower() == title.lower(): return guide return None # --- API Endpoints --- @app.get("/health", summary="Health Check", response_model=Dict[str, str]) async def health_check() -> Dict[str, str]: """Returns a simple status to indicate the server is running.""" logger.info("Health check requested.") return {"status": "ok", "service": APP_NAME, "version": APP_VERSION} @app.get( "/guides", response_model=List[Dict[str, str | List[str]]], summary="List all AI guides" ) async def list_ai_guides() -> List[Dict[str, str | List[str]]]: """Lists all available AI guides with their titles, publishers, descriptions, and topics. Returns: A list of dictionaries, each representing an AI guide's metadata. """ logger.info("Listing all AI guides.") return AI_GUIDES_DATA @app.get( "/guides/search", response_model=List[Dict[str, str | List[str]]], summary="Search for AI guides" ) async def search_ai_guides(query: str) -> List[Dict[str, str | List[str]]]: """Searches for AI guides based on keywords or topics in their title or description. Args: query: The keyword or topic to search for. Returns: A list of dictionaries for matching AI guides. """ logger.info(f"Searching AI guides with query: '{query}'.") query_lower = query.lower() results = [] for guide in AI_GUIDES_DATA: title_match = query_lower in guide["title"].lower() desc_match = query_lower in guide["description"].lower() topics_match = any(query_lower in topic.lower() for topic in guide.get("topics", [])) if title_match or desc_match or topics_match: results.append(guide) return results @app.get( "/guides/{title}", response_model=Dict[str, str | List[str]], summary="Get details of a specific AI guide" ) async def get_ai_guide_details(title: str) -> Dict[str, str | List[str]]: """Retrieves the full details of a specific AI guide by its exact title. Args: title: The exact title of the AI guide. Returns: A dictionary containing the full details of the AI guide. Raises: HTTPException: If the AI guide is not found (status code 404). """ logger.info(f"Fetching details for AI guide: '{title}'.") guide = _find_guide_by_title(title) if guide is None: logger.warning(f"AI guide not found: '{title}'.") raise HTTPException(status_code=404, detail="AI guide not found") return guide @app.get( "/guides/{title}/download-url", response_model=Dict[str, str], summary="Get download URL for a specific AI guide" ) async def get_ai_guide_download_url(title: str) -> Dict[str, str]: """Provides the direct download URL for a specific AI guide by its title. Args: title: The exact title of the AI guide. Returns: A dictionary containing the download URL. Raises: HTTPException: If the AI guide is not found (status code 404). """ logger.info(f"Fetching download URL for AI guide: '{title}'.") guide = _find_guide_by_title(title) if guide is None: logger.warning(f"AI guide not found for download URL: '{title}'.") raise HTTPException(status_code=404, detail="AI guide not found") # The type hint `str | List[str]` on AI_GUIDES_DATA forces a check here download_url_value = guide.get("download_url") if isinstance(download_url_value, str): return {"download_url": download_url_value} else: logger.error(f"Download URL for '{title}' is not a string: {download_url_value}") raise HTTPException(status_code=500, detail="Download URL not available or malformed") # --- Gemini-Enhanced Endpoints --- @app.post( "/guides/search/gemini", response_model=Dict[str, Any], summary="Search guides using Gemini AI with grounding" ) async def search_guides_with_gemini(request: GeminiSearchRequest) -> Dict[str, Any]: """Uses Gemini AI's grounding capabilities for intelligent semantic search across guides. Args: request: Search request with query and grounding option Returns: Search results with relevance scores and reasoning """ try: from gemini_service import get_gemini_service gemini = get_gemini_service() logger.info(f"Gemini search requested: '{request.query}' (grounding: {request.use_grounding})") if request.use_grounding: result = await gemini.search_with_grounding(request.query, AI_GUIDES_DATA) else: # Fallback to regular search if grounding not requested guides = await search_ai_guides(request.query) result = { "success": True, "grounded_search": False, "results": { "matched_guides": [g["title"] for g in guides], "search_reasoning": "Standard keyword-based search" } } return result except Exception as e: logger.error(f"Gemini search error: {str(e)}") raise HTTPException(status_code=500, detail=f"Gemini search failed: {str(e)}") @app.get( "/guides/{title}/analyze", response_model=Dict[str, Any], summary="Analyze guide content using Gemini AI" ) async def analyze_guide_with_gemini(title: str) -> Dict[str, Any]: """Analyzes a guide's content using Gemini AI to extract insights and summaries. Args: title: The exact title of the AI guide Returns: Enhanced analysis including summary, learning objectives, and recommendations """ try: guide = _find_guide_by_title(title) if guide is None: raise HTTPException(status_code=404, detail="AI guide not found") from gemini_service import get_gemini_service gemini = get_gemini_service() logger.info(f"Analyzing guide with Gemini: '{title}'") result = await gemini.generate_guide_summary(guide) return result except HTTPException: raise except Exception as e: logger.error(f"Gemini analysis error: {str(e)}") raise HTTPException(status_code=500, detail=f"Gemini analysis failed: {str(e)}") @app.post( "/guides/analyze-url", response_model=Dict[str, Any], summary="Analyze guide content from URL using Gemini AI" ) async def analyze_url_with_gemini(url: str = Query(..., description="URL of the guide to analyze")) -> Dict[str, Any]: """Fetches and analyzes content from a guide URL using Gemini AI. Args: url: URL of the guide to analyze Returns: Content analysis including topics, takeaways, and recommendations """ try: from gemini_service import get_gemini_service gemini = get_gemini_service() logger.info(f"Analyzing URL with Gemini: '{url}'") result = await gemini.analyze_guide_url(url) return result except Exception as e: logger.error(f"URL analysis error: {str(e)}") raise HTTPException(status_code=500, detail=f"URL analysis failed: {str(e)}") @app.post( "/guides/compare", response_model=Dict[str, Any], summary="Compare multiple guides using Gemini AI" ) async def compare_guides_with_gemini(request: GuideComparisonRequest) -> Dict[str, Any]: """Compares multiple AI guides to identify differences, overlaps, and recommendations. Args: request: List of guide titles to compare Returns: Comprehensive comparison including differences, overlaps, and reading order """ try: if len(request.guide_titles) < 2: raise HTTPException(status_code=400, detail="At least 2 guides required for comparison") if len(request.guide_titles) > 5: raise HTTPException(status_code=400, detail="Maximum 5 guides can be compared at once") from gemini_service import get_gemini_service gemini = get_gemini_service() logger.info(f"Comparing {len(request.guide_titles)} guides with Gemini") result = await gemini.compare_guides(request.guide_titles, AI_GUIDES_DATA) return result except HTTPException: raise except Exception as e: logger.error(f"Guide comparison error: {str(e)}") raise HTTPException(status_code=500, detail=f"Guide comparison failed: {str(e)}")

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ShunsukeHayashi/context_engineering_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server