Agents-MCP-Hackathon/Stack_Overflow_MCP_Server
2
1#!/usr/bin/env python32"""3Stack Exchange API Query Tool4 5This script allows you to directly call the Stack Exchange API with various parameters6and see the results. It's useful for testing queries and seeing the raw results.7 8Usage:9 python api_query.py search "python pandas dataframe" --tags python,pandas --min-score 1010 python api_query.py question 1234511 python api_query.py error "TypeError: cannot use a string pattern" --language python12"""13 14import os15import sys16import json17import asyncio18import argparse19from dotenv import load_dotenv20 21from stackoverflow_mcp.api import StackExchangeAPI22from stackoverflow_mcp.formatter import format_response23 24 25def setup_environment():26 """Load environment variables from .env file"""27 if os.path.exists(".env"):28 load_dotenv(".env")29 elif os.path.exists(".env.test"):30 load_dotenv(".env.test")31 else:32 print("Warning: No .env or .env.test file found. Using default settings.")33 34 35async def run_search_query(api, args):36 """Run a search query with the given arguments"""37 tags = args.tags.split(',') if args.tags else None38 39 excluded_tags = args.excluded_tags.split(',') if args.excluded_tags else None40 41 print(f"\nRunning search query: '{args.query}'")42 if args.title:43 print(f"Running search with title containing: '{args.title}'")44 if args.body:45 print(f"Running search with body containing: '{args.body}'")46 print(f"Tags: {tags}")47 print(f"Excluded tags: {excluded_tags}")48 print(f"Min score: {args.min_score}")49 print(f"Limit: {args.limit}")50 print(f"Include comments: {args.comments}\n")51 52 try:53 results = await api.search_by_query(54 query=args.query,55 tags=tags,56 title=args.title,57 body=args.body,58 excluded_tags=excluded_tags,59 min_score=args.min_score,60 limit=args.limit,61 include_comments=args.comments62 )63 64 print(f"Found {len(results)} results")65 66 if args.raw:67 for i, result in enumerate(results):68 print(f"\n--- Result {i+1} ---")69 print(f"Question ID: {result.question.question_id}")70 print(f"Title: {result.question.title}")71 print(f"Score: {result.question.score}")72 print(f"Tags: {result.question.tags}")73 print(f"Link: {result.question.link}")74 print(f"Answers: {len(result.answers)}")75 if result.comments:76 print(f"Question comments: {len(result.comments.question)}")77 else:78 formatted = format_response(results, args.format)79 print(formatted)80 81 except Exception as e:82 print(f"Error during search: {str(e)}")83 84 85async def run_question_query(api, args):86 """Get a specific question by ID"""87 try:88 print(f"\nFetching question ID: {args.question_id}")89 print(f"Include comments: {args.comments}\n")90 91 result = await api.get_question(92 question_id=args.question_id,93 include_comments=args.comments94 )95 96 if args.raw:97 print(f"Question ID: {result.question.question_id}")98 print(f"Title: {result.question.title}")99 print(f"Score: {result.question.score}")100 print(f"Tags: {result.question.tags}")101 print(f"Link: {result.question.link}")102 print(f"Answers: {len(result.answers)}")103 if result.comments:104 print(f"Question comments: {len(result.comments.question)}")105 else:106 formatted = format_response([result], args.format)107 print(formatted)108 109 except Exception as e:110 print(f"Error fetching question: {str(e)}")111 112 113async def run_error_query(api, args):114 """Search for an error message with optional language filter"""115 technologies = args.technologies.split(',') if args.technologies else None116 117 try:118 print(f"\nSearching for error: '{args.error}'")119 print(f"Language: {args.language}")120 print(f"Technologies: {technologies}")121 if args.title:122 print(f"Title containing: '{args.title}'")123 if args.body:124 print(f"Body containing: '{args.body}'")125 print(f"Min score: {args.min_score}")126 print(f"Limit: {args.limit}")127 print(f"Include comments: {args.comments}\n")128 129 tags = []130 if args.language:131 tags.append(args.language.lower())132 if technologies:133 tags.extend([t.lower() for t in technologies])134 135 results = await api.search_by_query(136 query=args.error,137 title=args.title,138 body=args.body,139 tags=tags if tags else None,140 min_score=args.min_score,141 limit=args.limit,142 include_comments=args.comments143 )144 145 print(f"Found {len(results)} results")146 147 if args.raw:148 for i, result in enumerate(results):149 print(f"\n--- Result {i+1} ---")150 print(f"Question ID: {result.question.question_id}")151 print(f"Title: {result.question.title}")152 print(f"Score: {result.question.score}")153 print(f"Tags: {result.question.tags}")154 print(f"Link: {result.question.link}")155 print(f"Answers: {len(result.answers)}")156 if result.comments:157 print(f"Question comments: {len(result.comments.question)}")158 else:159 formatted = format_response(results, args.format)160 print(formatted)161 162 except Exception as e:163 print(f"Error searching for error: {str(e)}")164 165 166async def main():167 """Parse arguments and run the appropriate query"""168 parser = argparse.ArgumentParser(description="Stack Exchange API Query Tool")169 subparsers = parser.add_subparsers(dest="command", help="Command to run")170 171 # Search command172 search_parser = subparsers.add_parser("search", help="Search Stack Overflow")173 search_parser.add_argument("query", help="Search query")174 search_parser.add_argument("--tags", help="Comma-separated list of tags")175 search_parser.add_argument("--title", help="Word(s) that must appear in the question title")176 search_parser.add_argument("--body", help="Word(s) that must appear in the body of the question")177 search_parser.add_argument("--excluded-tags", help="Comma-separated list of tags to exclude")178 search_parser.add_argument("--min-score", type=int, default=0, help="Minimum score")179 search_parser.add_argument("--limit", type=int, default=5, help="Maximum number of results")180 search_parser.add_argument("--comments", action="store_true", help="Include comments")181 search_parser.add_argument("--format", choices=["markdown", "json"], default="markdown", help="Output format")182 search_parser.add_argument("--raw", action="store_true", help="Print raw data structure")183 184 # Question command185 question_parser = subparsers.add_parser("question", help="Get a specific question")186 question_parser.add_argument("question_id", type=int, help="Question ID")187 question_parser.add_argument("--comments", action="store_true", help="Include comments")188 question_parser.add_argument("--format", choices=["markdown", "json"], default="markdown", help="Output format")189 question_parser.add_argument("--raw", action="store_true", help="Print raw data structure")190 191 # Error command192 error_parser = subparsers.add_parser("error", help="Search for an error message")193 error_parser.add_argument("error", help="Error message")194 error_parser.add_argument("--title", help="Word(s) that must appear in the question title")195 error_parser.add_argument("--body", help="Word(s) that must appear in the body of the question")196 error_parser.add_argument("--language", help="Programming language")197 error_parser.add_argument("--technologies", help="Comma-separated list of technologies")198 error_parser.add_argument("--min-score", type=int, default=0, help="Minimum score")199 error_parser.add_argument("--limit", type=int, default=5, help="Maximum number of results")200 error_parser.add_argument("--comments", action="store_true", help="Include comments")201 error_parser.add_argument("--format", choices=["markdown", "json"], default="markdown", help="Output format")202 error_parser.add_argument("--raw", action="store_true", help="Print raw data structure")203 204 args = parser.parse_args()205 206 if not args.command:207 parser.print_help()208 return 1209 210 setup_environment()211 212 api_key = os.getenv("STACK_EXCHANGE_API_KEY")213 214 if not api_key:215 print("Warning: No API key found. Requests may be rate limited.")216 217 api = StackExchangeAPI(api_key=api_key)218 219 try:220 if args.command == "search":221 await run_search_query(api, args)222 elif args.command == "question":223 await run_question_query(api, args)224 elif args.command == "error":225 await run_error_query(api, args)226 227 except Exception as e:228 print(f"Error: {str(e)}")229 return 1230 231 finally:232 await api.close()233 234 return 0235 236 237if __name__ == "__main__":238 sys.exit(asyncio.run(main()))