Skip to main content
Glama

Google Calendar MCP Server

by harshwadhawe
streamlit_app.pyโ€ข20.3 kB
#!/usr/bin/env python3 """ Project Management Assistant Dashboard A lightweight dashboard integrating GitHub, Google Calendar, and Slack for project management. """ import streamlit as st import sys import os from datetime import datetime, timedelta from dotenv import load_dotenv import pytz # Load environment variables load_dotenv() # Add src to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) from src.server import chat from src.calendar_client import CalendarClient from src.github_client import GitHubClient from src.slack_client import SlackClient from src.jira_client import JiraClient from src.query_analyzer import QueryAnalyzer # Page configuration st.set_page_config( page_title="Project Management Assistant", page_icon="๐Ÿ“Š", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for modern UI st.markdown(""" <style> .main-header { font-size: 3rem; font-weight: 700; text-align: center; margin-bottom: 0.5rem; } .mcp-highlight { background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 800; } .metric-card { background: white; padding: 1.5rem; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-left: 4px solid #667eea; } .event-card { background: #f8f9fa; padding: 1rem; border-radius: 8px; margin-bottom: 0.5rem; border-left: 3px solid #667eea; } .repo-card { background: #f8f9fa; padding: 1rem; border-radius: 8px; margin-bottom: 0.5rem; border-left: 3px solid #28a745; } .stTabs [data-baseweb="tab-list"] { gap: 8px; } .stTabs [data-baseweb="tab"] { border-radius: 8px 8px 0 0; padding: 10px 20px; } </style> """, unsafe_allow_html=True) # Initialize session state if "calendar_client" not in st.session_state: st.session_state.calendar_client = None if "github_client" not in st.session_state: st.session_state.github_client = None if "slack_client" not in st.session_state: st.session_state.slack_client = None if "jira_client" not in st.session_state: st.session_state.jira_client = None def initialize_clients(): """Initialize calendar, GitHub, Slack, and JIRA clients.""" try: if st.session_state.calendar_client is None: credentials_path = os.getenv("GOOGLE_CREDENTIALS_PATH", "config/credentials.json") token_path = os.getenv("GOOGLE_TOKEN_PATH", "config/token.json") # Redirect stdout during initialization to avoid interfering with Streamlit import sys original_stdout = sys.stdout try: sys.stdout = sys.stderr st.session_state.calendar_client = CalendarClient(credentials_path, token_path) finally: sys.stdout = original_stdout except Exception as e: st.session_state.calendar_client = None # Don't show error to user, just silently fail try: if st.session_state.github_client is None: st.session_state.github_client = GitHubClient() except Exception as e: st.session_state.github_client = None # Don't show error to user, just silently fail try: if st.session_state.slack_client is None: st.session_state.slack_client = SlackClient() except Exception as e: st.session_state.slack_client = None # Don't show error to user, just silently fail try: if st.session_state.jira_client is None: st.session_state.jira_client = JiraClient() except Exception as e: st.session_state.jira_client = None # Don't show error to user, just silently fail def format_time(dt_str): """Format datetime string for display.""" try: dt = datetime.fromisoformat(dt_str.replace('Z', '+00:00')) return dt.strftime('%I:%M %p') except: return dt_str def format_date(dt_str): """Format date string for display.""" try: dt = datetime.fromisoformat(dt_str.replace('Z', '+00:00')) return dt.strftime('%b %d, %Y') except: return dt_str def get_calendar_summary(): """Get calendar summary for today and upcoming week.""" if st.session_state.calendar_client is None: return [], [] try: now = datetime.now() today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) week_end = today_start + timedelta(days=7) events = st.session_state.calendar_client.get_events_from_all_calendars( time_min=today_start, time_max=week_end, max_results=50 ) today_events = [] upcoming_events = [] for event in events: start = event.get('start', {}).get('dateTime') or event.get('start', {}).get('date') if start: try: event_dt = datetime.fromisoformat(start.replace('Z', '+00:00')) event['parsed_start'] = event_dt if event_dt.date() == now.date(): today_events.append(event) elif event_dt.date() > now.date(): upcoming_events.append(event) except: pass # Sort events by time today_events.sort(key=lambda x: x.get('parsed_start', datetime.min)) upcoming_events.sort(key=lambda x: x.get('parsed_start', datetime.min)) return today_events, upcoming_events[:10] except Exception as e: return [], [] def get_github_summary(): """Get GitHub activity summary.""" if st.session_state.github_client is None: return None try: user_info = st.session_state.github_client.get_user_info() repos = st.session_state.github_client.get_repositories(per_page=10) # Get issues and PRs all_issues = [] all_prs = [] for repo in repos[:5]: owner = repo.get('owner', {}).get('login', user_info.get('login')) repo_name = repo.get('name', '') try: issues = st.session_state.github_client.get_issues(owner, repo_name, state='open', per_page=5) all_issues.extend(issues) except: pass try: prs = st.session_state.github_client.get_pull_requests(owner, repo_name, state='open', per_page=5) all_prs.extend(prs) except: pass return { 'user_info': user_info, 'repos': repos, 'open_issues': all_issues[:10], 'open_prs': all_prs[:10] } except Exception as e: return None def main(): # Header st.markdown('<h1 class="main-header">๐Ÿ“Š Project Management <span class="mcp-highlight">MCP Server</span> Assistant</h1>', unsafe_allow_html=True) # Initialize clients initialize_clients() # Sidebar with st.sidebar: st.header("โš™๏ธ Settings") if st.button("๐Ÿ”„ Refresh Data", use_container_width=True): st.session_state.calendar_client = None st.session_state.github_client = None st.session_state.slack_client = None st.session_state.jira_client = None initialize_clients() st.rerun() st.divider() # Status indicators st.subheader("๐Ÿ”Œ Connections") calendar_status = "โœ… Connected" if st.session_state.calendar_client else "โŒ Not Connected" github_status = "โœ… Connected" if st.session_state.github_client else "โŒ Not Connected" slack_status = "โœ… Connected" if st.session_state.slack_client else "โŒ Not Connected" jira_status = "โœ… Connected" if st.session_state.jira_client else "โŒ Not Connected" st.write(f"**Calendar:** {calendar_status}") st.write(f"**GitHub:** {github_status}") st.write(f"**Slack:** {slack_status}") st.write(f"**JIRA:** {jira_status}") if not st.session_state.calendar_client: st.info("๐Ÿ’ก Configure Google Calendar credentials to enable calendar features.") if not st.session_state.github_client: st.info("๐Ÿ’ก Set GITHUB_TOKEN in .env to enable GitHub features.") if not st.session_state.slack_client: st.info("๐Ÿ’ก Set SLACK_USER_TOKEN in .env to enable Slack features.") if not st.session_state.jira_client: st.info("๐Ÿ’ก Set JIRA_BASE_URL, JIRA_EMAIL, and JIRA_API_TOKEN in .env to enable JIRA features.") st.divider() st.subheader("๐Ÿ’ฌ AI Assistant") st.caption("Ask questions about your projects, schedule, GitHub activity, Slack messages, or JIRA issues") # Main content - AI Assistant only st.header("๐Ÿ’ฌ AI Assistant") st.caption("Ask me anything about your projects, schedule, GitHub activity, Slack messages, or JIRA issues") # Predefined queries organized by category st.subheader("๐Ÿ“‹ Predefined Queries") # Calendar queries st.markdown("#### ๐Ÿ“… Calendar & Schedule") col1, col2, col3 = st.columns(3) with col1: if st.button("๐Ÿ“… What's my schedule today?", use_container_width=True): st.session_state.quick_query = "What's my schedule today?" st.rerun() if st.button("๐Ÿ“† What meetings do I have this week?", use_container_width=True): st.session_state.quick_query = "What meetings do I have this week?" st.rerun() if st.button("โฐ When am I free tomorrow?", use_container_width=True): st.session_state.quick_query = "When am I free tomorrow?" st.rerun() with col2: if st.button("๐Ÿ“‹ Summarize my schedule for Monday", use_container_width=True): st.session_state.quick_query = "Summarize my schedule for Monday" st.rerun() if st.button("๐Ÿ” Am I free next week?", use_container_width=True): st.session_state.quick_query = "Am I free next week?" st.rerun() if st.button("๐Ÿ“Š Show upcoming events", use_container_width=True): st.session_state.quick_query = "Show me my upcoming events" st.rerun() with col3: if st.button("โณ Check availability at 2 PM", use_container_width=True): st.session_state.quick_query = "Am I available tomorrow at 2 PM?" st.rerun() if st.button("๐Ÿ“… What's on my calendar next week?", use_container_width=True): st.session_state.quick_query = "What's on my calendar next week?" st.rerun() if st.button("๐Ÿ”Ž Detect scheduling conflicts", use_container_width=True): st.session_state.quick_query = "Are there any scheduling conflicts this week?" st.rerun() st.divider() # GitHub queries st.markdown("#### ๐Ÿ™ GitHub & Repositories") col1, col2, col3 = st.columns(3) with col1: if st.button("๐Ÿ“ฆ Show my repositories", use_container_width=True): st.session_state.quick_query = "Show me my recent repositories" st.rerun() if st.button("๐Ÿ› What issues need attention?", use_container_width=True): st.session_state.quick_query = "What are my open issues?" st.rerun() if st.button("๐Ÿ”€ Show open pull requests", use_container_width=True): st.session_state.quick_query = "What PRs are open in my repos?" st.rerun() with col2: if st.button("๐Ÿš€ Show current deployments", use_container_width=True): st.session_state.quick_query = "Show current deployments setup on GitHub" st.rerun() if st.button("๐Ÿ“ Recent commits", use_container_width=True): st.session_state.quick_query = "Show me my recent commits" st.rerun() if st.button("๐Ÿ“Š GitHub activity summary", use_container_width=True): st.session_state.quick_query = "Give me a summary of my GitHub activity" st.rerun() with col3: if st.button("๐Ÿ” Search repositories", use_container_width=True): st.session_state.quick_query = "What repositories do I have?" st.rerun() if st.button("๐Ÿ“ˆ Production deployments", use_container_width=True): st.session_state.quick_query = "What deployments are live in production?" st.rerun() if st.button("๐Ÿ“š Repository details", use_container_width=True): st.session_state.quick_query = "Tell me about my repositories" st.rerun() st.divider() # Slack queries st.markdown("#### ๐Ÿ’ฌ Slack & Messages") col1, col2, col3 = st.columns(3) with col1: if st.button("๐Ÿ“ฌ Unread Slack messages", use_container_width=True): st.session_state.quick_query = "What are my unread Slack messages?" st.rerun() if st.button("๐Ÿ”” Recent mentions", use_container_width=True): st.session_state.quick_query = "Show me my recent Slack mentions" st.rerun() if st.button("๐Ÿ“‹ List Slack channels", use_container_width=True): st.session_state.quick_query = "Show me my Slack channels" st.rerun() with col2: if st.button("๐Ÿ’ฌ Channel activity", use_container_width=True): st.session_state.quick_query = "What's happening in my Slack channels?" st.rerun() if st.button("๐Ÿ” Search messages", use_container_width=True): st.session_state.quick_query = "Search my Slack messages" st.rerun() if st.button("๐Ÿ“Š Slack summary", use_container_width=True): st.session_state.quick_query = "Give me a summary of my Slack activity" st.rerun() with col3: if st.button("๐Ÿ“จ Direct messages", use_container_width=True): st.session_state.quick_query = "Show me my Slack direct messages" st.rerun() if st.button("๐Ÿงต Thread activity", use_container_width=True): st.session_state.quick_query = "What Slack threads need my attention?" st.rerun() if st.button("๐Ÿ“ˆ Activity overview", use_container_width=True): st.session_state.quick_query = "What's my Slack activity overview?" st.rerun() st.divider() # JIRA queries st.markdown("#### ๐ŸŽฏ JIRA & Issues") col1, col2, col3 = st.columns(3) with col1: if st.button("๐ŸŽซ My JIRA issues", use_container_width=True): st.session_state.quick_query = "What JIRA issues are assigned to me?" st.rerun() if st.button("๐Ÿ“‹ List JIRA boards", use_container_width=True): st.session_state.quick_query = "Show me my JIRA boards" st.rerun() if st.button("๐Ÿ“ฆ Backlog items", use_container_width=True): st.session_state.quick_query = "Show me JIRA backlog items" st.rerun() with col2: if st.button("๐Ÿ“Š JIRA activity", use_container_width=True): st.session_state.quick_query = "What's my JIRA activity?" st.rerun() if st.button("๐Ÿ› My bugs", use_container_width=True): st.session_state.quick_query = "Show me my JIRA bugs" st.rerun() if st.button("โœ… In progress tasks", use_container_width=True): st.session_state.quick_query = "What JIRA tasks are in progress?" st.rerun() with col3: if st.button("๐Ÿ“ˆ Sprint issues", use_container_width=True): st.session_state.quick_query = "What issues are in my sprint?" st.rerun() if st.button("๐ŸŽฏ High priority", use_container_width=True): st.session_state.quick_query = "Show me high priority JIRA issues" st.rerun() if st.button("๐Ÿ“ JIRA summary", use_container_width=True): st.session_state.quick_query = "Give me a summary of my JIRA issues" st.rerun() st.divider() # Custom query input st.subheader("๐Ÿ’ญ Custom Query") user_input = st.text_input("Enter your question:", placeholder="e.g., What meetings do I have today?") # Process user input if user_input: with st.spinner("Thinking..."): try: # Auto-detect query types message_lower = user_input.lower() include_github = any(keyword in message_lower for keyword in ['github', 'repo', 'repository', 'issue', 'pr', 'pull request', 'commit', 'deployment', 'deploy', 'deployed', 'deploying', 'production', 'staging']) include_slack = any(keyword in message_lower for keyword in ['slack', 'message', 'messages', 'channel', 'channels', 'mention', 'mentions', 'unread', 'dm', 'direct message', 'thread', 'threads']) include_jira = any(keyword in message_lower for keyword in ['jira', 'jql', 'board', 'boards', 'sprint', 'sprints', 'ticket', 'tickets', 'issue', 'issues', 'task', 'tasks', 'story', 'stories', 'bug', 'bugs', 'assigned to me', 'my issues', 'my tickets', 'backlog', 'backlog items']) response = chat( message=user_input, include_calendar_context=True, include_github_context=include_github, include_slack_context=include_slack, include_jira_context=include_jira ) st.markdown("### Response:") st.write(response) except Exception as e: error_msg = f"Error: {str(e)}" st.error(error_msg) # Handle quick query if hasattr(st.session_state, 'quick_query') and st.session_state.quick_query: query = st.session_state.quick_query del st.session_state.quick_query with st.spinner("Thinking..."): try: message_lower = query.lower() include_github = any(keyword in message_lower for keyword in ['github', 'repo', 'repository', 'issue', 'pr', 'pull request', 'commit', 'deployment', 'deploy', 'deployed', 'deploying', 'production', 'staging']) include_slack = any(keyword in message_lower for keyword in ['slack', 'message', 'messages', 'channel', 'channels', 'mention', 'mentions', 'unread', 'dm', 'direct message', 'thread', 'threads']) include_jira = any(keyword in message_lower for keyword in ['jira', 'jql', 'board', 'boards', 'sprint', 'sprints', 'ticket', 'tickets', 'issue', 'issues', 'task', 'tasks', 'story', 'stories', 'bug', 'bugs', 'assigned to me', 'my issues', 'my tickets', 'backlog', 'backlog items']) response = chat( message=query, include_calendar_context=True, include_github_context=include_github, include_slack_context=include_slack, include_jira_context=include_jira ) st.markdown("### Response:") st.write(response) except Exception as e: st.error(f"Error: {str(e)}") if __name__ == "__main__": main()

Latest Blog Posts

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/harshwadhawe/MCP-server--datathon'

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