Tech Trends Agent π
A robust, scalable AI-powered web service combining FastAPI, Pydantic-AI, and MCP servers
This project demonstrates how to build a production-ready AI-powered web service by combining three cutting-edge, open-source technologies:
FastAPI for high-performance asynchronous APIs Pydantic-AI for type-safe, schema-driven agent construction Model Context Protocol (MCP) servers as plug-and-play tools
A quick glance at the UI: type a question, choose sources (Hacker News and/or Web Search), then get ranked trend cards with scores, links, and an AI-written summaryβso you can quickly see what's trending about any topic or technology.
π― What You'll Learn
Advanced data modeling patterns with Pydantic
Multi-agent AI systems with A2A communication
MCP server integration for extensible AI tools
Production-ready FastAPI deployment patterns
Docker containerization for AI services
Type-safe AI agent development
ποΈ Architecture
flowchart TD subgraph UI["π Web UI + Docs"] U["π€ User"] -->|HTTP| FA["π FastAPI
(app/main.py)"] end subgraph CORE["π― Orchestration"] dummy[" "]:::hidden FA --> AM["AgentManager"] AM --> GA["π€ GeneralAgent
Classifier / Chat"] AM --> EA["π€ EntryAgent
Tech Radar"] AM --> SA["π€ SpecialistAgent
Repo Intel"] GA -->|handoff| EA EA <--> A2A["A2A Protocol"] SA <--> A2A end subgraph TOOLS["π Tooling"] EA --> BS["π Brave Search MCP
(active)"] EA --> HN["π° Hacker News MCP
(active)"] SA --> GH["π GitHub MCP
(optional)"] EA --> FS["π Filesystem MCP
(optional)"] SA --> FS end classDef agent fill:#ffffff,color:#111827,stroke:#60a5fa,stroke-width:2px,rx:10,ry:10 classDef svc fill:#f8fafc,color:#111827,stroke:#0288d1,stroke-width:2px,rx:10,ry:10 classDef toolActive fill:#ffffff,color:#111827,stroke:#16a34a,stroke-width:2px,rx:10,ry:10 classDef toolDisabled fill:#ffffff,color:#111827,stroke:#f59e0b,stroke-width:2px,rx:10,ry:10 classDef hidden fill:transparent,stroke:transparent class EA,GA,SA agent class FA,AM,A2A svc class BS,HN toolActive class GH toolDisabled Loading π Quick Start (Docker - Recommended) Prerequisites Docker and Docker Compose OpenAI API key (required) GitHub token (optional, for enhanced GitHub features) 1. Clone and Setup git clone < your-repo-url > cd Tech_Trends_Agent 2. Configure Environment # Copy environment template cp env.example .env # Edit .env with your API keys vi .env # or your preferred editor Required environment variables: OPENAI_API_KEY = your_openai_api_key_here GITHUB_TOKEN = your_github_token_here # Optional but recommended BRAVE_API_KEY = your_brave_api_key 3. Start the App # Start with Docker (recommended) ./docker-start.sh # Or manually with docker-compose docker-compose up --build -d 4. Access the Application Web UI : http://localhost:8000/ui : http://localhost:8000/ui Interactive API Documentation : http://localhost:8000/docs : http://localhost:8000/docs ReDoc Documentation : http://localhost:8000/redoc : http://localhost:8000/redoc Health Check: http://localhost:8000/health 5. Stop the App # Stop the application ./docker-stop.sh # Or manually docker-compose down π Development Setup (Alternative) If you prefer to run without Docker: # Create and activate virtual environment python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install dependencies pip install -e . # Start the application python -m app.main π API Endpoints Core Analysis Endpoints π Tech Trends Analysis POST /api/v1/trends Content-Type: application/json { "query" : " latest AI frameworks " , "limit" : 10 , "include_hn" : true , "include_brave" : true } π Repository Intelligence POST /api/v1/repositories Content-Type: application/json { "repositories" : [ " tiangolo/fastapi " , " pydantic/pydantic-ai " ], "include_metrics" : true , "include_recent_activity" : true } π Combined Analysis POST /api/v1/combined-analysis Content-Type: application/json { "query" : " Python web frameworks 2024 " , "auto_detect_repos" : true , "max_repos" : 5 , "trend_limit" : 15 } π§ Unified Assistant (Intent Routing) POST /api/v1/assistant Content-Type: application/json { "input" : " Where is Athens? " , "limit" : 10 , "include_hn" : true , "include_brave" : true } Response when routed to chat: { "route" : " chat " , "data" : { "response" : " ... " , "message_type" : " general " , "timestamp" : " ... " }, "timestamp" : " ... " } Response when routed to trends: { "route" : " trends " , "data" : { "query" : " ... " , "trends" : [ ... ], "summary" : " ... " , "analysis_timestamp" : " ... " }, "timestamp" : " ... " } Other helpful endpoints: GET /api/v1/agents/status GET /api/v1/mcp/status GET /api/v1/files GET /api/v1/history , GET /api/v1/history/{id} Monitoring Endpoints GET /health - Application health check - Application health check GET /api/v1/agents/status - Agent status information - Agent status information GET /api/v1/mcp/status - MCP server status π€ Agent System Entry Agent (Tech Radar) Analyzes technology trends using Brave Search and Hacker News Identifies emerging technologies and frameworks Detects GitHub repositories mentioned in trends Delegates repository analysis to Specialist Agent Specialist Agent (Repo Intel) Performs detailed GitHub repository analysis Provides repository health metrics and insights Correlates repository data with technology trends Generates competitive analysis and recommendations A2A Communication Agents communicate through Pydantic-AI's Agent-to-Agent (A2A) protocol: Type-safe message passing Correlation tracking Error handling and retries π§ MCP Server Integration What are MCP Servers? Model Context Protocol (MCP) servers provide standardized interfaces for AI tools: Pluggable Architecture : Easy to add new capabilities : Easy to add new capabilities Type Safety : Schema-driven tool definitions : Schema-driven tool definitions Scalability : Distributed tool execution : Distributed tool execution Security: Sandboxed tool execution Available Tools Hacker News MCP (Active) Top stories and trending content via MCP tools Filtered by relevance and recency Status: β Active (see hackernews-mcp-custom ) Brave Search MCP (Active) Brave Search API integration via MCP server Structured results with relevance and quality scoring Status: β Active (see brave-search-mcp-custom ) GitHub MCP (Disabled by default) Repository search and details Status: β Disabled by default; enable in docker-compose.yml and provide GITHUB_TOKEN Filesystem MCP (Disabled) Secure file operations Read-only data access Status: β Disabled (local file listing is exposed via /api/v1/files instead) π³ Docker Deployment Quick Start (Recommended) # Start Tech Tracker with one command ./docker-start.sh # Stop Tech Tracker ./docker-stop.sh Manual Docker Commands # Build and start docker-compose up --build -d # View logs docker-compose logs -f # Stop services docker-compose down Production Deployment # Build production image docker build -t tech-tracker:latest . # Run with production settings docker run -d \ --name tech-tracker \ -p 8000:8000 \ -e OPENAI_API_KEY= " your_key " \ -e ENVIRONMENT= " production " \ tech-tracker:latest Current Tooling Status (from code and compose) Brave Search MCP: β active on port 3001 Hacker News MCP: β active on port 3003 GitHub MCP: β disabled by default (uncomment in compose to enable) Filesystem MCP: β disabled by default π§ͺ Testing # Install development dependencies pip install -e " .[dev] " # Run tests pytest # Run tests with coverage pytest --cov=app --cov-report=html # Type checking mypy app/ π§Ή Code Quality Basic commands to format, lint, and scan the codebase: Black (format) Format repo: black . Check only: black --check . Ruff (lint + fixes) Lint: ruff check . Autofix: ruff check . --fix Bandit (security scan) Scan app code: bandit -r app Output to file: bandit -r app -f txt -o bandit-report.txt π Project Structure HN_Github_Agents/ βββ app/ β βββ agents/ # AI agent implementations β β βββ base_agent.py β β βββ entry_agent.py β β βββ specialist_agent.py β βββ models/ # Pydantic data models β β βββ requests.py β β βββ responses.py β β βββ schemas.py β βββ services/ # Business logic services β β βββ a2a_service.py # A2A protocol (Pydantic-AI) β β βββ agent_manager.py # orchestrates agents + MCP β βββ utils/ # Utilities and configuration β β βββ config.py β β βββ logging.py β β βββ mcp_client.py β βββ main.py # FastAPI application βββ data/ # Sample data for filesystem MCP βββ static/ # Web interface files βββ scripts/ # Setup and utility scripts βββ tests/ # Test suite βββ docker-compose.yml # Docker services configuration βββ Dockerfile # Application container βββ docker-start.sh # Quick start script βββ docker-stop.sh # Quick stop script βββ pyproject.toml # Project configuration π Example Usage Analyze Python Web Framework Trends import httpx async def analyze_python_trends (): async with httpx . AsyncClient () as client : response = await client . post ( "http://localhost:8000/api/v1/combined-analysis" , json = { "query" : "Python web frameworks 2024 FastAPI Django Flask" , "auto_detect_repos" : True , "max_repos" : 5 , "trend_limit" : 20 } ) result = response . json () print ( f"Trends found: { result [ 'trends' ][ 'total_items' ] } " ) print ( f"Repositories analyzed: { result [ 'repositories' ][ 'total_repos' ] } " ) print ( f"Recommendations: { len ( result [ 'recommendations' ]) } " ) return result Monitor Repository Health repositories = [ "tiangolo/fastapi" , "django/django" , "pallets/flask" , "pydantic/pydantic-ai" ] async def monitor_repos (): async with httpx . AsyncClient () as client : response = await client . post ( "http://localhost:8000/api/v1/repositories" , json = { "repositories" : repositories , "include_metrics" : True , "include_recent_activity" : True } ) result = response . json () for repo in result [ 'repositories' ]: stars = repo [ 'metrics' ][ 'stars' ] health = "π’" if stars > 10000 else "π‘" if stars > 1000 else "π΄" print ( f" { health } { repo [ 'full_name' ] } : { stars :, } stars" ) π¨ Advanced Features Custom MCP Server Integration Add your own MCP servers by: Updating docker-compose.yml: custom-mcp : image : your/custom-mcp-server ports : - " 3005:3005 " environment : - CUSTOM_API_KEY=${CUSTOM_API_KEY} Registering in the agent: @ self . agent . tool async def custom_tool ( ctx : RunContext [ Any ], param : str ) -> Dict [ str , Any ]: client = self . mcp_manager . get_client ( "custom" ) return await client . call_tool ( "custom_operation" , { "param" : param }) Extending Agent Capabilities Create new agents by inheriting from BaseAgent : from app . agents . base_agent import BaseAgent class CustomAgent ( BaseAgent ): def __init__ ( self ): system_prompt = "You are a custom analysis agent..." super (). __init__ ( "custom_agent" , system_prompt ) async def process_request ( self , request_data : Dict [ str , Any ]) -> Dict [ str , Any ]: # Your custom logic here pass π§ Configuration Options Key configuration options in app/utils/config.py : from app . utils . config import settings # MCP URLs (compose overrides for in-container calls) settings . brave_search_mcp_url # default http://localhost:3001 settings . github_mcp_url # default http://localhost:3002 (disabled in compose) settings . hacker_news_mcp_url # default http://localhost:3003 settings . filesystem_mcp_url # default http://localhost:3004 # App settings . log_level # INFO by default settings . environment # development by default settings . hn_stories_limit # default 50 (HN MCP fetch window) settings . web_search_limit # default 20 (Brave MCP) π Troubleshooting Common Issues MCP Servers Not Starting # Check Docker status docker ps # Restart MCP servers ./scripts/setup_mcp_servers.sh restart # Check server logs docker logs brave-search-mcp API Rate Limiting GitHub: Ensure GITHUB_TOKEN is set for higher rate limits is set for higher rate limits Hacker News: Built-in rate limiting prevents overloading Agent Initialization Errors # Check OpenAI API key curl -H " Authorization: Bearer $OPENAI_API_KEY " \ https://api.openai.com/v1/models # Verify MCP server connectivity curl http://localhost:3001/health Debug Mode Enable debug logging: export LOG_LEVEL=DEBUG python -m app.main π€ Contributing Fork the repository Create a feature branch Make your changes Add tests for new functionality Ensure all tests pass Submit a pull request Development Setup # Install development dependencies pip install -e " .[dev] " # Set up pre-commit hooks pre-commit install # Run the full test suite pytest --cov=app π Resources π License This project is licensed under the MIT License - see the LICENSE file for details. π€ PyCon Presentation This project was created as a demonstration for a PyCon tutorial: "Building Robust AI Web Services with FastAPI, Pydantic-AI, and MCP Servers" In this 60-minute tutorial, learn how to build a production-ready AI-powered web service that combines high-performance APIs, type-safe agent construction, and pluggable tool integration. π’ Understanding the Scoring System The application uses dynamic scoring based on real data from active sources: Score Origins Web Search Results (1-100 Scale) - Active Scoring Based on: Search relevance, domain authority, content match Algorithm: Enhanced relevance calculation with quality bonuses Location: app/agents/entry_agent.py:1614-1680 Factors: Title matches (25-35pts), URL matches (15pts), Quality domains (+25pts) Hacker News Stories (1-100 Scale) - Live Weighted Scoring Based on: HN points (50%) + Relevance (40%) + Recency (10%) Algorithm: Weighted combination of multiple factors Location: app/agents/entry_agent.py:1130-1164 Filters: Stories must be recent (within 60 days) and relevant Repository Health (0.0-1.0 Scale) - Calculated from GitHub API Based on: Stars (30%), Forks (20%), Activity (30%), Diversity (20%) Algorithm: Normalized weighted scoring Location: app/agents/specialist_agent.py:328-360 Real-time data from GitHub API (when available) Current System Status β Active Sources : Hacker News MCP, Brave Search MCP : Hacker News MCP, Brave Search MCP β οΈ Fallback Mode : GitHub API (direct calls when MCP unavailable) : GitHub API (direct calls when MCP unavailable) β Disabled : Filesystem MCP : Filesystem MCP Health Check: Visit /health endpoint to see real-time status π Detailed System Architecture Complete Request Flow (Assistant Route) sequenceDiagram participant U as User participant UI as Frontend UI participant FA as FastAPI Server participant AM as Agent Manager participant EA as Entry Agent
(Tech Radar) participant SA as Specialist Agent
(Repo Intel) participant A2A as A2A Protocol participant BS as Brave Search MCP participant HN as Hacker News MCP participant GH as GitHub MCP (opt) Note over U,GH: Complete Tech Trends Analysis Flow U->>UI: Enter query "Docker development tools" UI->>FA: POST /api/v1/assistant FA->>AM: route_user_intent() AM->>GA: process_request(message) alt TECH GA-->>AM: handoff payload AM->>EA: process_request(query_data) else GENERAL GA-->>AM: direct answer AM-->>FA: AssistantRouteResponse(route="chat") FA-->>UI: Render chat end Note over EA,GH: Entry Agent Processing EA->>EA: Classify query as tech-related EA->>BS: Brave Search MCP call BS-->>EA: Web search results (structured JSON) EA->>HN: search_stories via MCP HN-->>EA: HN stories (filtered and scored) EA->>EA: Generate AI analysis summary EA->>EA: Extract GitHub repositories EA->>EA: Calculate confidence score alt If repositories detected EA->>A2A: delegate_to_specialist() A2A->>SA: send_message(repo_analysis_request) Note over SA,GH: Specialist Agent Processing SA->>GH: get_repository/search (if enabled) GH-->>SA: repo data SA->>SA: Generate correlation analysis SA->>SA: Calculate repo health scores SA->>A2A: send_message(repo_analysis_response) A2A-->>EA: Repository intelligence results end EA-->>AM: Complete trends analysis AM-->>FA: Formatted response FA-->>UI: TechTrendsResponse JSON UI->>UI: renderMarkdown(summary) UI->>UI: Display trend cards UI-->>U: Results Note over U,GH: General Chat Flow (Alternative) U->>UI: "Where is Athens?" UI->>FA: POST /api/v1/chat FA->>EA: process_general_chat() EA->>EA: Classify as general (non-tech) EA->>EA: Generate direct AI response EA-->>FA: General chat response FA-->>UI: GeneralChatResponse UI->>UI: renderMarkdown() for AI response UI-->>U: Formatted chat response Note over U,GH: Health Check & Status UI->>FA: GET /health FA->>AM: health_check() AM->>HN: health_check() - β Active AM->>A2A: health_check() AM-->>FA: System health status FA-->>UI: HealthResponse UI->>UI: Update status indicators Loading System Architecture & Data Flow flowchart TD %% User Interface Layer U[π€ User] --> UI[π Frontend UI
Vanilla JS SPA] UI --> |HTTP Requests| FA[π FastAPI Server
Port 8000] %% API Layer FA --> |Dependency Injection| AM[π― Agent Manager
Orchestration Hub] %% Agent Layer AM --> EA[π€ Entry Agent
Tech Radar
Pydantic AI] AM --> SA[π€ Specialist Agent
Repo Intel
Pydantic AI] %% A2A Communication EA <--> |Agent-to-Agent
Messages| A2A[π‘ A2A Protocol] SA <--> A2A %% Data Sources Layer EA --> |MCP Active β | BS[π Brave Search MCP] EA --> |MCP Active β | HN[π° Hacker News MCP] SA --> |MCP opt β| GH[π GitHub MCP] AM --> |Local Files| FD[π Local Data Access
JSON Files] %% External APIs BS --> |MCP Protocol| BE[π Brave Search API] HN --> |MCP Protocol| HE[π‘ Hacker News API] GH --> |REST API| GE[π± GitHub REST API] %% Processing Flow subgraph "π¨ Frontend Processing" UI --> MD[π Markdown Renderer
marked.js + Prism.js] UI --> SC[β Score Display
Dynamic Scoring] UI --> TC[ποΈ Trend Cards
Interactive UI] end subgraph "π§ AI Processing" EA --> |System Prompt| EP[π Tech Analysis
OpenAI GPT] SA --> |System Prompt| SP[π Repo Intelligence
OpenAI GPT] EP --> |Generates| AS[π Analysis Summary
Markdown Format] SP --> |Generates| RI[π Repo Insights
Correlation Scores] end subgraph "π Scoring System" BS --> |Relevance + Quality| S1[β Web Score
1-100 Scale] HN --> |HN Points + Recency| S2[β HN Score
Weighted Algorithm] GH --> |Stars/Forks/Activity| S3[β Repo Health
0.0-1.0 Scale] end subgraph "π§ Configuration" CF[βοΈ Config Files
.env
settings.py] CF --> AM CF --> EA CF --> SA end %% Status Indicators HN -.-> |Status: Active β | ST1[Functional MCP] BS -.-> |Status: Active β | ST2[Full MCP Server] GH -.-> |Status: Fallback β οΈ| ST3[Demo Mode] %% Styling classDef userLayer fill:#e1f5fe,stroke:#01579b,stroke-width:2px,color:#000 classDef apiLayer fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,color:#000 classDef agentLayer fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px,color:#000 classDef activeLayer fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#000 classDef fallbackLayer fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#000 classDef externalLayer fill:#fce4ec,stroke:#880e4f,stroke-width:2px,color:#000 classDef dataLayer fill:#f1f8e9,stroke:#33691e,stroke-width:2px,color:#000 class U,UI userLayer class FA,AM apiLayer class EA,SA,A2A agentLayer class BS,ST1 activeLayer class HN activeLayer class GH,ST3 fallbackLayer class BE,HE,GE externalLayer class FD,CF,MD,SC,TC,EP,SP,AS,RI,S1,S2,S3 dataLayer Loading Key Architecture Components π― Agent Manager ( AgentManager ) Purpose : Central orchestration hub for all agents and services : Central orchestration hub for all agents and services Location : app/services/agent_manager.py : Responsibilities : Initialize and manage agent lifecycle Route requests to appropriate agents Coordinate A2A communication Manage MCP client connections Health monitoring and error handling : π€ Entry Agent ( EntryAgent ) Purpose : Tech trend analysis and general AI assistance : Tech trend analysis and general AI assistance Location : app/agents/entry_agent.py : Capabilities : Brave Search MCP integration for web trends Hacker News story fetching and analysis GitHub repository detection from trends General chat for non-tech queries A2A delegation to Specialist Agent : π€ Specialist Agent ( SpecialistAgent ) Purpose : GitHub repository intelligence and analysis : GitHub repository intelligence and analysis Location : app/agents/specialist_agent.py : Capabilities : Repository metrics analysis (stars, forks, activity) Technology ecosystem mapping Correlation score calculation Growth potential assessment Competitive landscape insights : π‘ A2A Protocol ( A2AService ) Purpose : Agent-to-Agent communication using Pydantic-AIβs A2A protocol ( agent.to_a2a() ) : Agent-to-Agent communication using Pydantic-AIβs A2A protocol ( ) Location : app/services/a2a_service.py : Notes : Registers agents and can expose ASGI handlers for A2A endpoints send_message routes messages via the protocol; HTTP handlers return results immediately : π§ MCP Client Manager ( MCPClientManager ) Purpose : Manage connections to available MCP servers : Manage connections to available MCP servers Location : app/utils/mcp_client.py : Servers : Hacker News MCP (Port 3003): β Story fetching and trends Brave Search MCP (Port 3001): β Web search with rich metadata GitHub MCP (Port 3002): β Disabled (uses direct API fallback) Filesystem MCP (Port 3004): β Disabled (uses local file access) : π Data Flow Patterns Tech Trends Flow: User β UI β FastAPI β Entry Agent β HN MCP + Brave MCP β AI Analysis β Response Repository Analysis: Entry Agent β A2A Protocol β Specialist Agent β GitHub MCP (optional) β Intelligence Report General Chat: User β UI β FastAPI β Entry Agent (Direct AI) β Response Health Monitoring: UI β FastAPI β Agent Manager β Active Services β Status Report File Processing: @filename syntax β Local file system access β Content injection ποΈ Current Implementation Status What's Working β Hacker News Integration : Full MCP server with real-time story fetching : Full MCP server with real-time story fetching β Web Search : Brave Search MCP server with structured API responses : Brave Search MCP server with structured API responses β AI Analysis : OpenAI GPT-powered trend analysis and insights : OpenAI GPT-powered trend analysis and insights β A2A Communication : Agent-to-agent messaging system : Agent-to-agent messaging system β File Processing : @filename syntax for including data files : @filename syntax for including data files β Interactive UI: Full-featured web interface with markdown rendering Demo/Fallback Mode β οΈ GitHub Analysis : Uses direct API calls instead of MCP server : Uses direct API calls instead of MCP server β οΈ Repository Intelligence: Works with fallback data and API calls Future Enhancements π Additional MCP Servers : GitHub, Filesystem : GitHub, Filesystem π Enhanced Integrations : Full MCP protocol implementation : Full MCP protocol implementation π Production Deployment: Scalable containerized architecture Ready to build your own AI-powered web service? π This implementation demonstrates real-world FastAPI + Pydantic-AI + MCP integration patterns! In short
(app/main.py)"] end subgraph CORE["π― Orchestration"] dummy[" "]:::hidden FA --> AM["AgentManager"] AM --> GA["π€ GeneralAgent
Classifier / Chat"] AM --> EA["π€ EntryAgent
Tech Radar"] AM --> SA["π€ SpecialistAgent
Repo Intel"] GA -->|handoff| EA EA <--> A2A["A2A Protocol"] SA <--> A2A end subgraph TOOLS["π Tooling"] EA --> BS["π Brave Search MCP
(active)"] EA --> HN["π° Hacker News MCP
(active)"] SA --> GH["π GitHub MCP
(optional)"] EA --> FS["π Filesystem MCP
(optional)"] SA --> FS end classDef agent fill:#ffffff,color:#111827,stroke:#60a5fa,stroke-width:2px,rx:10,ry:10 classDef svc fill:#f8fafc,color:#111827,stroke:#0288d1,stroke-width:2px,rx:10,ry:10 classDef toolActive fill:#ffffff,color:#111827,stroke:#16a34a,stroke-width:2px,rx:10,ry:10 classDef toolDisabled fill:#ffffff,color:#111827,stroke:#f59e0b,stroke-width:2px,rx:10,ry:10 classDef hidden fill:transparent,stroke:transparent class EA,GA,SA agent class FA,AM,A2A svc class BS,HN toolActive class GH toolDisabled Loading π Quick Start (Docker - Recommended) Prerequisites Docker and Docker Compose OpenAI API key (required) GitHub token (optional, for enhanced GitHub features) 1. Clone and Setup git clone < your-repo-url > cd Tech_Trends_Agent 2. Configure Environment # Copy environment template cp env.example .env # Edit .env with your API keys vi .env # or your preferred editor Required environment variables: OPENAI_API_KEY = your_openai_api_key_here GITHUB_TOKEN = your_github_token_here # Optional but recommended BRAVE_API_KEY = your_brave_api_key 3. Start the App # Start with Docker (recommended) ./docker-start.sh # Or manually with docker-compose docker-compose up --build -d 4. Access the Application Web UI : http://localhost:8000/ui : http://localhost:8000/ui Interactive API Documentation : http://localhost:8000/docs : http://localhost:8000/docs ReDoc Documentation : http://localhost:8000/redoc : http://localhost:8000/redoc Health Check: http://localhost:8000/health 5. Stop the App # Stop the application ./docker-stop.sh # Or manually docker-compose down π Development Setup (Alternative) If you prefer to run without Docker: # Create and activate virtual environment python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install dependencies pip install -e . # Start the application python -m app.main π API Endpoints Core Analysis Endpoints π Tech Trends Analysis POST /api/v1/trends Content-Type: application/json { "query" : " latest AI frameworks " , "limit" : 10 , "include_hn" : true , "include_brave" : true } π Repository Intelligence POST /api/v1/repositories Content-Type: application/json { "repositories" : [ " tiangolo/fastapi " , " pydantic/pydantic-ai " ], "include_metrics" : true , "include_recent_activity" : true } π Combined Analysis POST /api/v1/combined-analysis Content-Type: application/json { "query" : " Python web frameworks 2024 " , "auto_detect_repos" : true , "max_repos" : 5 , "trend_limit" : 15 } π§ Unified Assistant (Intent Routing) POST /api/v1/assistant Content-Type: application/json { "input" : " Where is Athens? " , "limit" : 10 , "include_hn" : true , "include_brave" : true } Response when routed to chat: { "route" : " chat " , "data" : { "response" : " ... " , "message_type" : " general " , "timestamp" : " ... " }, "timestamp" : " ... " } Response when routed to trends: { "route" : " trends " , "data" : { "query" : " ... " , "trends" : [ ... ], "summary" : " ... " , "analysis_timestamp" : " ... " }, "timestamp" : " ... " } Other helpful endpoints: GET /api/v1/agents/status GET /api/v1/mcp/status GET /api/v1/files GET /api/v1/history , GET /api/v1/history/{id} Monitoring Endpoints GET /health - Application health check - Application health check GET /api/v1/agents/status - Agent status information - Agent status information GET /api/v1/mcp/status - MCP server status π€ Agent System Entry Agent (Tech Radar) Analyzes technology trends using Brave Search and Hacker News Identifies emerging technologies and frameworks Detects GitHub repositories mentioned in trends Delegates repository analysis to Specialist Agent Specialist Agent (Repo Intel) Performs detailed GitHub repository analysis Provides repository health metrics and insights Correlates repository data with technology trends Generates competitive analysis and recommendations A2A Communication Agents communicate through Pydantic-AI's Agent-to-Agent (A2A) protocol: Type-safe message passing Correlation tracking Error handling and retries π§ MCP Server Integration What are MCP Servers? Model Context Protocol (MCP) servers provide standardized interfaces for AI tools: Pluggable Architecture : Easy to add new capabilities : Easy to add new capabilities Type Safety : Schema-driven tool definitions : Schema-driven tool definitions Scalability : Distributed tool execution : Distributed tool execution Security: Sandboxed tool execution Available Tools Hacker News MCP (Active) Top stories and trending content via MCP tools Filtered by relevance and recency Status: β Active (see hackernews-mcp-custom ) Brave Search MCP (Active) Brave Search API integration via MCP server Structured results with relevance and quality scoring Status: β Active (see brave-search-mcp-custom ) GitHub MCP (Disabled by default) Repository search and details Status: β Disabled by default; enable in docker-compose.yml and provide GITHUB_TOKEN Filesystem MCP (Disabled) Secure file operations Read-only data access Status: β Disabled (local file listing is exposed via /api/v1/files instead) π³ Docker Deployment Quick Start (Recommended) # Start Tech Tracker with one command ./docker-start.sh # Stop Tech Tracker ./docker-stop.sh Manual Docker Commands # Build and start docker-compose up --build -d # View logs docker-compose logs -f # Stop services docker-compose down Production Deployment # Build production image docker build -t tech-tracker:latest . # Run with production settings docker run -d \ --name tech-tracker \ -p 8000:8000 \ -e OPENAI_API_KEY= " your_key " \ -e ENVIRONMENT= " production " \ tech-tracker:latest Current Tooling Status (from code and compose) Brave Search MCP: β active on port 3001 Hacker News MCP: β active on port 3003 GitHub MCP: β disabled by default (uncomment in compose to enable) Filesystem MCP: β disabled by default π§ͺ Testing # Install development dependencies pip install -e " .[dev] " # Run tests pytest # Run tests with coverage pytest --cov=app --cov-report=html # Type checking mypy app/ π§Ή Code Quality Basic commands to format, lint, and scan the codebase: Black (format) Format repo: black . Check only: black --check . Ruff (lint + fixes) Lint: ruff check . Autofix: ruff check . --fix Bandit (security scan) Scan app code: bandit -r app Output to file: bandit -r app -f txt -o bandit-report.txt π Project Structure HN_Github_Agents/ βββ app/ β βββ agents/ # AI agent implementations β β βββ base_agent.py β β βββ entry_agent.py β β βββ specialist_agent.py β βββ models/ # Pydantic data models β β βββ requests.py β β βββ responses.py β β βββ schemas.py β βββ services/ # Business logic services β β βββ a2a_service.py # A2A protocol (Pydantic-AI) β β βββ agent_manager.py # orchestrates agents + MCP β βββ utils/ # Utilities and configuration β β βββ config.py β β βββ logging.py β β βββ mcp_client.py β βββ main.py # FastAPI application βββ data/ # Sample data for filesystem MCP βββ static/ # Web interface files βββ scripts/ # Setup and utility scripts βββ tests/ # Test suite βββ docker-compose.yml # Docker services configuration βββ Dockerfile # Application container βββ docker-start.sh # Quick start script βββ docker-stop.sh # Quick stop script βββ pyproject.toml # Project configuration π Example Usage Analyze Python Web Framework Trends import httpx async def analyze_python_trends (): async with httpx . AsyncClient () as client : response = await client . post ( "http://localhost:8000/api/v1/combined-analysis" , json = { "query" : "Python web frameworks 2024 FastAPI Django Flask" , "auto_detect_repos" : True , "max_repos" : 5 , "trend_limit" : 20 } ) result = response . json () print ( f"Trends found: { result [ 'trends' ][ 'total_items' ] } " ) print ( f"Repositories analyzed: { result [ 'repositories' ][ 'total_repos' ] } " ) print ( f"Recommendations: { len ( result [ 'recommendations' ]) } " ) return result Monitor Repository Health repositories = [ "tiangolo/fastapi" , "django/django" , "pallets/flask" , "pydantic/pydantic-ai" ] async def monitor_repos (): async with httpx . AsyncClient () as client : response = await client . post ( "http://localhost:8000/api/v1/repositories" , json = { "repositories" : repositories , "include_metrics" : True , "include_recent_activity" : True } ) result = response . json () for repo in result [ 'repositories' ]: stars = repo [ 'metrics' ][ 'stars' ] health = "π’" if stars > 10000 else "π‘" if stars > 1000 else "π΄" print ( f" { health } { repo [ 'full_name' ] } : { stars :, } stars" ) π¨ Advanced Features Custom MCP Server Integration Add your own MCP servers by: Updating docker-compose.yml: custom-mcp : image : your/custom-mcp-server ports : - " 3005:3005 " environment : - CUSTOM_API_KEY=${CUSTOM_API_KEY} Registering in the agent: @ self . agent . tool async def custom_tool ( ctx : RunContext [ Any ], param : str ) -> Dict [ str , Any ]: client = self . mcp_manager . get_client ( "custom" ) return await client . call_tool ( "custom_operation" , { "param" : param }) Extending Agent Capabilities Create new agents by inheriting from BaseAgent : from app . agents . base_agent import BaseAgent class CustomAgent ( BaseAgent ): def __init__ ( self ): system_prompt = "You are a custom analysis agent..." super (). __init__ ( "custom_agent" , system_prompt ) async def process_request ( self , request_data : Dict [ str , Any ]) -> Dict [ str , Any ]: # Your custom logic here pass π§ Configuration Options Key configuration options in app/utils/config.py : from app . utils . config import settings # MCP URLs (compose overrides for in-container calls) settings . brave_search_mcp_url # default http://localhost:3001 settings . github_mcp_url # default http://localhost:3002 (disabled in compose) settings . hacker_news_mcp_url # default http://localhost:3003 settings . filesystem_mcp_url # default http://localhost:3004 # App settings . log_level # INFO by default settings . environment # development by default settings . hn_stories_limit # default 50 (HN MCP fetch window) settings . web_search_limit # default 20 (Brave MCP) π Troubleshooting Common Issues MCP Servers Not Starting # Check Docker status docker ps # Restart MCP servers ./scripts/setup_mcp_servers.sh restart # Check server logs docker logs brave-search-mcp API Rate Limiting GitHub: Ensure GITHUB_TOKEN is set for higher rate limits is set for higher rate limits Hacker News: Built-in rate limiting prevents overloading Agent Initialization Errors # Check OpenAI API key curl -H " Authorization: Bearer $OPENAI_API_KEY " \ https://api.openai.com/v1/models # Verify MCP server connectivity curl http://localhost:3001/health Debug Mode Enable debug logging: export LOG_LEVEL=DEBUG python -m app.main π€ Contributing Fork the repository Create a feature branch Make your changes Add tests for new functionality Ensure all tests pass Submit a pull request Development Setup # Install development dependencies pip install -e " .[dev] " # Set up pre-commit hooks pre-commit install # Run the full test suite pytest --cov=app π Resources π License This project is licensed under the MIT License - see the LICENSE file for details. π€ PyCon Presentation This project was created as a demonstration for a PyCon tutorial: "Building Robust AI Web Services with FastAPI, Pydantic-AI, and MCP Servers" In this 60-minute tutorial, learn how to build a production-ready AI-powered web service that combines high-performance APIs, type-safe agent construction, and pluggable tool integration. π’ Understanding the Scoring System The application uses dynamic scoring based on real data from active sources: Score Origins Web Search Results (1-100 Scale) - Active Scoring Based on: Search relevance, domain authority, content match Algorithm: Enhanced relevance calculation with quality bonuses Location: app/agents/entry_agent.py:1614-1680 Factors: Title matches (25-35pts), URL matches (15pts), Quality domains (+25pts) Hacker News Stories (1-100 Scale) - Live Weighted Scoring Based on: HN points (50%) + Relevance (40%) + Recency (10%) Algorithm: Weighted combination of multiple factors Location: app/agents/entry_agent.py:1130-1164 Filters: Stories must be recent (within 60 days) and relevant Repository Health (0.0-1.0 Scale) - Calculated from GitHub API Based on: Stars (30%), Forks (20%), Activity (30%), Diversity (20%) Algorithm: Normalized weighted scoring Location: app/agents/specialist_agent.py:328-360 Real-time data from GitHub API (when available) Current System Status β Active Sources : Hacker News MCP, Brave Search MCP : Hacker News MCP, Brave Search MCP β οΈ Fallback Mode : GitHub API (direct calls when MCP unavailable) : GitHub API (direct calls when MCP unavailable) β Disabled : Filesystem MCP : Filesystem MCP Health Check: Visit /health endpoint to see real-time status π Detailed System Architecture Complete Request Flow (Assistant Route) sequenceDiagram participant U as User participant UI as Frontend UI participant FA as FastAPI Server participant AM as Agent Manager participant EA as Entry Agent
(Tech Radar) participant SA as Specialist Agent
(Repo Intel) participant A2A as A2A Protocol participant BS as Brave Search MCP participant HN as Hacker News MCP participant GH as GitHub MCP (opt) Note over U,GH: Complete Tech Trends Analysis Flow U->>UI: Enter query "Docker development tools" UI->>FA: POST /api/v1/assistant FA->>AM: route_user_intent() AM->>GA: process_request(message) alt TECH GA-->>AM: handoff payload AM->>EA: process_request(query_data) else GENERAL GA-->>AM: direct answer AM-->>FA: AssistantRouteResponse(route="chat") FA-->>UI: Render chat end Note over EA,GH: Entry Agent Processing EA->>EA: Classify query as tech-related EA->>BS: Brave Search MCP call BS-->>EA: Web search results (structured JSON) EA->>HN: search_stories via MCP HN-->>EA: HN stories (filtered and scored) EA->>EA: Generate AI analysis summary EA->>EA: Extract GitHub repositories EA->>EA: Calculate confidence score alt If repositories detected EA->>A2A: delegate_to_specialist() A2A->>SA: send_message(repo_analysis_request) Note over SA,GH: Specialist Agent Processing SA->>GH: get_repository/search (if enabled) GH-->>SA: repo data SA->>SA: Generate correlation analysis SA->>SA: Calculate repo health scores SA->>A2A: send_message(repo_analysis_response) A2A-->>EA: Repository intelligence results end EA-->>AM: Complete trends analysis AM-->>FA: Formatted response FA-->>UI: TechTrendsResponse JSON UI->>UI: renderMarkdown(summary) UI->>UI: Display trend cards UI-->>U: Results Note over U,GH: General Chat Flow (Alternative) U->>UI: "Where is Athens?" UI->>FA: POST /api/v1/chat FA->>EA: process_general_chat() EA->>EA: Classify as general (non-tech) EA->>EA: Generate direct AI response EA-->>FA: General chat response FA-->>UI: GeneralChatResponse UI->>UI: renderMarkdown() for AI response UI-->>U: Formatted chat response Note over U,GH: Health Check & Status UI->>FA: GET /health FA->>AM: health_check() AM->>HN: health_check() - β Active AM->>A2A: health_check() AM-->>FA: System health status FA-->>UI: HealthResponse UI->>UI: Update status indicators Loading System Architecture & Data Flow flowchart TD %% User Interface Layer U[π€ User] --> UI[π Frontend UI
Vanilla JS SPA] UI --> |HTTP Requests| FA[π FastAPI Server
Port 8000] %% API Layer FA --> |Dependency Injection| AM[π― Agent Manager
Orchestration Hub] %% Agent Layer AM --> EA[π€ Entry Agent
Tech Radar
Pydantic AI] AM --> SA[π€ Specialist Agent
Repo Intel
Pydantic AI] %% A2A Communication EA <--> |Agent-to-Agent
Messages| A2A[π‘ A2A Protocol] SA <--> A2A %% Data Sources Layer EA --> |MCP Active β | BS[π Brave Search MCP] EA --> |MCP Active β | HN[π° Hacker News MCP] SA --> |MCP opt β| GH[π GitHub MCP] AM --> |Local Files| FD[π Local Data Access
JSON Files] %% External APIs BS --> |MCP Protocol| BE[π Brave Search API] HN --> |MCP Protocol| HE[π‘ Hacker News API] GH --> |REST API| GE[π± GitHub REST API] %% Processing Flow subgraph "π¨ Frontend Processing" UI --> MD[π Markdown Renderer
marked.js + Prism.js] UI --> SC[β Score Display
Dynamic Scoring] UI --> TC[ποΈ Trend Cards
Interactive UI] end subgraph "π§ AI Processing" EA --> |System Prompt| EP[π Tech Analysis
OpenAI GPT] SA --> |System Prompt| SP[π Repo Intelligence
OpenAI GPT] EP --> |Generates| AS[π Analysis Summary
Markdown Format] SP --> |Generates| RI[π Repo Insights
Correlation Scores] end subgraph "π Scoring System" BS --> |Relevance + Quality| S1[β Web Score
1-100 Scale] HN --> |HN Points + Recency| S2[β HN Score
Weighted Algorithm] GH --> |Stars/Forks/Activity| S3[β Repo Health
0.0-1.0 Scale] end subgraph "π§ Configuration" CF[βοΈ Config Files
.env
settings.py] CF --> AM CF --> EA CF --> SA end %% Status Indicators HN -.-> |Status: Active β | ST1[Functional MCP] BS -.-> |Status: Active β | ST2[Full MCP Server] GH -.-> |Status: Fallback β οΈ| ST3[Demo Mode] %% Styling classDef userLayer fill:#e1f5fe,stroke:#01579b,stroke-width:2px,color:#000 classDef apiLayer fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,color:#000 classDef agentLayer fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px,color:#000 classDef activeLayer fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#000 classDef fallbackLayer fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#000 classDef externalLayer fill:#fce4ec,stroke:#880e4f,stroke-width:2px,color:#000 classDef dataLayer fill:#f1f8e9,stroke:#33691e,stroke-width:2px,color:#000 class U,UI userLayer class FA,AM apiLayer class EA,SA,A2A agentLayer class BS,ST1 activeLayer class HN activeLayer class GH,ST3 fallbackLayer class BE,HE,GE externalLayer class FD,CF,MD,SC,TC,EP,SP,AS,RI,S1,S2,S3 dataLayer Loading Key Architecture Components π― Agent Manager ( AgentManager ) Purpose : Central orchestration hub for all agents and services : Central orchestration hub for all agents and services Location : app/services/agent_manager.py : Responsibilities : Initialize and manage agent lifecycle Route requests to appropriate agents Coordinate A2A communication Manage MCP client connections Health monitoring and error handling : π€ Entry Agent ( EntryAgent ) Purpose : Tech trend analysis and general AI assistance : Tech trend analysis and general AI assistance Location : app/agents/entry_agent.py : Capabilities : Brave Search MCP integration for web trends Hacker News story fetching and analysis GitHub repository detection from trends General chat for non-tech queries A2A delegation to Specialist Agent : π€ Specialist Agent ( SpecialistAgent ) Purpose : GitHub repository intelligence and analysis : GitHub repository intelligence and analysis Location : app/agents/specialist_agent.py : Capabilities : Repository metrics analysis (stars, forks, activity) Technology ecosystem mapping Correlation score calculation Growth potential assessment Competitive landscape insights : π‘ A2A Protocol ( A2AService ) Purpose : Agent-to-Agent communication using Pydantic-AIβs A2A protocol ( agent.to_a2a() ) : Agent-to-Agent communication using Pydantic-AIβs A2A protocol ( ) Location : app/services/a2a_service.py : Notes : Registers agents and can expose ASGI handlers for A2A endpoints send_message routes messages via the protocol; HTTP handlers return results immediately : π§ MCP Client Manager ( MCPClientManager ) Purpose : Manage connections to available MCP servers : Manage connections to available MCP servers Location : app/utils/mcp_client.py : Servers : Hacker News MCP (Port 3003): β Story fetching and trends Brave Search MCP (Port 3001): β Web search with rich metadata GitHub MCP (Port 3002): β Disabled (uses direct API fallback) Filesystem MCP (Port 3004): β Disabled (uses local file access) : π Data Flow Patterns Tech Trends Flow: User β UI β FastAPI β Entry Agent β HN MCP + Brave MCP β AI Analysis β Response Repository Analysis: Entry Agent β A2A Protocol β Specialist Agent β GitHub MCP (optional) β Intelligence Report General Chat: User β UI β FastAPI β Entry Agent (Direct AI) β Response Health Monitoring: UI β FastAPI β Agent Manager β Active Services β Status Report File Processing: @filename syntax β Local file system access β Content injection ποΈ Current Implementation Status What's Working β Hacker News Integration : Full MCP server with real-time story fetching : Full MCP server with real-time story fetching β Web Search : Brave Search MCP server with structured API responses : Brave Search MCP server with structured API responses β AI Analysis : OpenAI GPT-powered trend analysis and insights : OpenAI GPT-powered trend analysis and insights β A2A Communication : Agent-to-agent messaging system : Agent-to-agent messaging system β File Processing : @filename syntax for including data files : @filename syntax for including data files β Interactive UI: Full-featured web interface with markdown rendering Demo/Fallback Mode β οΈ GitHub Analysis : Uses direct API calls instead of MCP server : Uses direct API calls instead of MCP server β οΈ Repository Intelligence: Works with fallback data and API calls Future Enhancements π Additional MCP Servers : GitHub, Filesystem : GitHub, Filesystem π Enhanced Integrations : Full MCP protocol implementation : Full MCP protocol implementation π Production Deployment: Scalable containerized architecture Ready to build your own AI-powered web service? π This implementation demonstrates real-world FastAPI + Pydantic-AI + MCP integration patterns! In short