Skip to main content
Glama
main.pyโ€ข3.91 kB
import os import time import logging from dotenv import load_dotenv from pathlib import Path from fastapi import FastAPI, HTTPException # Load environment variables from the script's directory env_path = Path(__file__).parent / '.env' load_dotenv(dotenv_path=env_path) # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) if os.path.exists(env_path): logger.info(f"Loading .env from: {env_path}") else: logger.warning(f".env file NOT found at: {env_path}") if os.getenv('GEMINI_API_KEY'): logger.info("GEMINI_API_KEY found in environment.") else: logger.error("GEMINI_API_KEY NOT found in environment.") # Import Models from pydantic_models import ( GrantsQueryInput, GrantsQueryOutput, GrantOpportunity, PitchGenerateInput, PitchGenerateOutput, GoogleServicesInput ) # Import Modules from grants_gov_api import GrantsGovAPI from pitch_generator import PitchGenerator from google_services_manager import GoogleServicesManager app = FastAPI(title="Grant Hunter MCP") # Instantiate Services grants_api = GrantsGovAPI() pitch_generator = PitchGenerator() google_services_manager = GoogleServicesManager() @app.get("/health") async def health_check(): """Health check endpoint for container orchestration.""" return {"status": "healthy"} @app.post("/query_grants", response_model=GrantsQueryOutput) async def query_grants(input_data: GrantsQueryInput): """ Query Grants.gov for opportunities. """ start_time = time.time() try: # Use the keyword from input results = grants_api.search_grants( input_data.keyword, limit=input_data.max_results ) # Map to GrantOpportunity model grant_opportunities = [] for r in results: grant_opportunities.append( GrantOpportunity( id=r.get('opportunity_number', 'UNKNOWN'), title=r.get('title', 'Unknown'), agency=r.get('agency', 'Unknown'), close_date=r.get('close_date', 'Unknown'), status="Open", data_status="COMPLETE" ) ) execution_time = (time.time() - start_time) * 1000 return GrantsQueryOutput( results=grant_opportunities, total_count=len(grant_opportunities), execution_time_ms=execution_time ) except Exception as e: logger.error(f"Critical error in query_grants: {str(e)}") # Graceful degradation execution_time = (time.time() - start_time) * 1000 # Return mock data with INCOMPLETE status if everything fails mock_results = [] for m in GrantsGovAPI.MOCK_GRANTS: mock_results.append( GrantOpportunity( id=m.get('opportunity_number', 'UNKNOWN'), title=m.get('title', 'Unknown'), agency=m.get('agency', 'Unknown'), close_date=m.get('close_date', 'Unknown'), status="Open", data_status="INCOMPLETE_SYNOPSIS_ONLY" ) ) return GrantsQueryOutput( results=mock_results[:input_data.max_results], total_count=len(mock_results), execution_time_ms=execution_time ) @app.post("/generate_pitch", response_model=PitchGenerateOutput) async def generate_pitch(input_data: PitchGenerateInput): """ Generate a funding pitch using Gemini or fallback template. """ return pitch_generator.generate_pitch(input_data) @app.post("/manage_google_services") async def manage_google_services(input_data: GoogleServicesInput): """ Manage Google Services: Create Gmail draft and Calendar event. """ return google_services_manager.execute_services(input_data)

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/vitor-giacomelli/mcp-grant-hunter'

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