Skip to main content
Glama

TimeLooker MCP Server

deploy_infrastructure.pyโ€ข9.11 kB
#!/usr/bin/env python3 """ Deploy AWS infrastructure for TimeLooker MCP Server using CDK. """ import os import sys import subprocess import json from pathlib import Path def run_command(command, cwd=None): """Run a shell command and return the result.""" print(f"Running: {command}") result = subprocess.run(command, shell=True, cwd=cwd, capture_output=True, text=True) if result.returncode != 0: print(f"Error: {result.stderr}") sys.exit(1) return result.stdout.strip() def get_default_email_template(): """Default HTML email template for notifications.""" return """<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TimeLooker Notification</title> <style> body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; } .header { background: #2c3e50; color: white; padding: 20px; text-align: center; border-radius: 5px 5px 0 0; } .content { background: #f8f9fa; padding: 20px; border: 1px solid #dee2e6; } .footer { background: #6c757d; color: white; padding: 15px; text-align: center; border-radius: 0 0 5px 5px; font-size: 0.9em; } .item { background: white; margin: 10px 0; padding: 15px; border-left: 4px solid #007bff; border-radius: 3px; } .item h3 { margin: 0 0 10px 0; color: #007bff; } .item .meta { color: #6c757d; font-size: 0.9em; margin: 5px 0; } .item .description { margin: 10px 0; } .item .url { word-break: break-all; } </style> </head> <body> <div class="header"> <h1>๐Ÿ” TimeLooker Notification</h1> <p>New items found for your monitoring task</p> </div> <div class="content"> <h2>Task: {{task_description}}</h2> <p><strong>Time:</strong> {{timestamp}}</p> <p><strong>New items found:</strong> {{new_items_count}}</p> <h3>New Items:</h3> {{#new_items}} <div class="item"> <h3>{{name}}</h3> <div class="meta"> <strong>Source:</strong> {{source}} | <strong>Location:</strong> {{location}} </div> {{#description}} <div class="description">{{description}}</div> {{/description}} {{#url}} <div class="meta"> <strong>URL:</strong> <a href="{{url}}" target="_blank">{{url}}</a> </div> {{/url}} {{#additional_info}} <div class="meta"> <strong>Additional Info:</strong> {{additional_info}} </div> {{/additional_info}} </div> {{/new_items}} </div> <div class="footer"> <p>This is an automated message from TimeLooker MCP Server</p> <p>Powered by AWS Lambda, RDS, and SES</p> </div> </body> </html>""" def main(): """Deploy the CDK infrastructure.""" project_root = Path(__file__).parent.parent infrastructure_dir = project_root / "infrastructure" print("๐Ÿš€ Deploying TimeLooker AWS Infrastructure...") # Check if AWS CLI is configured try: run_command("aws sts get-caller-identity") print("โœ… AWS CLI is configured") except: print("โŒ AWS CLI not configured. Please run 'aws configure' first.") sys.exit(1) # Check if CDK is installed try: run_command("cdk --version") print("โœ… AWS CDK is available") except: print("โŒ AWS CDK not installed. Please install with 'npm install -g aws-cdk'") sys.exit(1) # Install CDK dependencies print("\n๐Ÿ“ฆ Installing CDK dependencies...") run_command("pip install -r requirements.txt", cwd=infrastructure_dir) # Bootstrap CDK (if needed) print("\n๐Ÿ—๏ธ Bootstrapping CDK...") try: run_command("cdk bootstrap --region eu-west-2", cwd=infrastructure_dir) print("โœ… CDK bootstrap completed") except: print("โ„น๏ธ CDK bootstrap may have already been done") # Deploy the stack print("\n๐Ÿš€ Deploying TimeLooker stack...") # Set environment variable to silence Node.js version warning env = os.environ.copy() env['JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION'] = '1' result = subprocess.run( "cdk deploy --require-approval never --outputs-file outputs.json", shell=True, cwd=infrastructure_dir, capture_output=True, text=True, env=env ) if result.returncode != 0: print(f"Error: {result.stderr}") sys.exit(1) deploy_output = result.stdout.strip() # Read outputs outputs_file = infrastructure_dir / "outputs.json" if outputs_file.exists(): with open(outputs_file) as f: outputs = json.load(f) stack_outputs = outputs.get("TimeLookerStack", {}) print("\nโœ… Infrastructure deployed successfully!") print("\n๐Ÿ“‹ Stack Outputs:") for key, value in stack_outputs.items(): print(f" {key}: {value}") # Upload email template to S3 bucket_name = stack_outputs.get('EmailTemplatesBucket', '') if bucket_name: print(f"\n๐Ÿ“ง Uploading email template to S3 bucket: {bucket_name}") try: # Create temporary email template file template_content = get_default_email_template() template_file = project_root / "temp_email_template.html" with open(template_file, 'w') as f: f.write(template_content) # Upload to S3 run_command(f"aws s3 cp {template_file} s3://{bucket_name}/notification_template.html") print("โœ… Email template uploaded successfully") # Clean up temp file template_file.unlink() except Exception as e: print(f"โš ๏ธ Failed to upload email template: {e}") print("You can upload it manually later") # Create .env.aws file with actual values env_file = project_root / ".env.aws" print(f"\n๐Ÿ“ Creating {env_file}...") env_content = f"""# AWS Cloud Deployment Configuration for TimeLooker MCP Server # Generated automatically by deploy_infrastructure.py # Deployment Mode DEPLOY_TO_CLOUD=true # AWS Infrastructure - All credentials retrieved from AWS Secrets Manager # AWS_REGION is automatically detected from AWS CLI/environment DATABASE_SECRET_ARN={stack_outputs.get('DatabaseSecretArn', '')} OPENAI_SECRET_ARN={stack_outputs.get('OpenAISecretArn', '')} X402_SECRET_ARN={stack_outputs.get('X402SecretArn', '')} LAMBDA_EXECUTION_ROLE_ARN={stack_outputs.get('LambdaExecutionRoleArn', '')} EMAIL_TEMPLATES_BUCKET={stack_outputs.get('EmailTemplatesBucket', '')} # Database Configuration - Retrieved automatically from DATABASE_SECRET_ARN # DATABASE_URL is set automatically from AWS Secrets Manager # Database endpoint: {stack_outputs.get('DatabaseEndpoint', '')}:{stack_outputs.get('DatabasePort', '5432')}/{stack_outputs.get('DatabaseName', 'timelooker')} # x402 Payment Configuration - Retrieved automatically from X402_SECRET_ARN # PRIVATE_KEY is set automatically from AWS Secrets Manager PAY_TO_ADDRESS=0x671cE47E4F38051ba3A990Ba306E2885C2Fe4102 # API Configuration TASK_MANAGER_API_URL=http://localhost:8000 # Email Configuration DEFAULT_SENDER_EMAIL=fortnightlydevs@gmail.com # Logging LOG_LEVEL=INFO # Note: OPENAI_API_KEY, DATABASE_URL, and PRIVATE_KEY are automatically # retrieved from AWS Secrets Manager when DEPLOY_TO_CLOUD=true """ with open(env_file, 'w') as f: f.write(env_content) print(f"โœ… Created {env_file}") # Post-deployment instructions print("\n๐Ÿ”ง Post-Deployment Setup Required:") print("1. Update the secrets in AWS Secrets Manager:") print(f" - OpenAI API Key: aws secretsmanager update-secret --secret-id {stack_outputs.get('OpenAISecretArn', '')} --secret-string '{{\"api_key\":\"your_openai_key_here\"}}'") print(f" - X402 Private Key: aws secretsmanager update-secret --secret-id {stack_outputs.get('X402SecretArn', '')} --secret-string '{{\"private_key\":\"your_private_key_here\"}}'") print("\n2. Verify your email address in SES:") print(f" - Email Identity: {stack_outputs.get('SESEmailIdentity', '')}") print(" - Go to AWS Console > SES > Verified identities > Verify the email") print("\n3. Update .env.aws with your private key and sender email") print("\n4. Initialize the database:") print(" python scripts/init_db.py --reset --sample") else: print("โš ๏ธ No outputs file found, but deployment may have succeeded") print("\n๐ŸŽ‰ Infrastructure deployment complete!") if __name__ == "__main__": main()

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/fortnightly-devs/mcp-x402-task-scheduler'

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