Spaces:
Build error
Build error
| import asyncio | |
| import os | |
| import logging | |
| from fastapi import FastAPI, Request, Response | |
| # Set up logging | |
| logging.basicConfig(level=logging.DEBUG) | |
| logger = logging.getLogger(__name__) | |
| app = FastAPI() | |
| proc = None | |
| async def startup_event(): | |
| global proc | |
| # Get the token from an environment variable on the Hugging Face Space | |
| # This is a more secure way to handle the token | |
| token = os.environ.get("GITHUB_PERSONAL_ACCESS_TOKEN") | |
| logger.info("Attempting to start subprocess...") | |
| logger.info("Token environment variable exists: %s", token is not None) | |
| if not token: | |
| logger.error("GITHUB_PERSONAL_ACCESS_TOKEN environment variable not set") | |
| return | |
| logger.info("Starting subprocess with token: %s", token[:10] + "...") | |
| try: | |
| proc = await asyncio.create_subprocess_exec( | |
| '/usr/local/bin/github-mcp-server', 'stdio', | |
| stdin=asyncio.subprocess.PIPE, | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE, | |
| env={"GITHUB_PERSONAL_ACCESS_TOKEN": token} | |
| ) | |
| logger.info("Subprocess created successfully with PID: %s", proc.pid) | |
| # Test if subprocess is actually running | |
| if proc.returncode is None: | |
| logger.info("Subprocess appears to be running") | |
| else: | |
| logger.warning("Subprocess may have exited immediately with code: %s", proc.returncode) | |
| asyncio.create_task(log_stderr()) | |
| except Exception as e: | |
| logger.error("Failed to create subprocess: %s", str(e)) | |
| raise | |
| async def log_stderr(): | |
| if proc and proc.stderr: | |
| logger.info("Starting stderr logging task") | |
| while not proc.stderr.at_eof(): | |
| try: | |
| line = await proc.stderr.readline() | |
| if line: | |
| logger.debug("github-mcp-server stderr: %s", line.decode().strip()) | |
| else: | |
| logger.debug("Empty line from stderr") | |
| except Exception as e: | |
| logger.error("Error reading stderr: %s", str(e)) | |
| break | |
| async def proxy(request: Request): | |
| if not proc or not proc.stdin or not proc.stdout: | |
| logger.error("Subprocess not running") | |
| return Response(status_code=500, content="Subprocess not running") | |
| # Log incoming request | |
| body = await request.body() | |
| logger.info("Received request: %s", body.decode()) | |
| # Token verification for debugging | |
| import requests | |
| token = os.environ.get("GITHUB_PERSONAL_ACCESS_TOKEN") | |
| if token: | |
| try: | |
| response = requests.get("https://api.github.com/user", headers={"Authorization": f"token {token}"}) | |
| if response.status_code == 200: | |
| logger.info("GitHub token verification successful") | |
| else: | |
| logger.error("GitHub token verification failed with status code: %s", response.status_code) | |
| except Exception as e: | |
| logger.error("Error verifying GitHub token: %s", str(e)) | |
| # Send to subprocess | |
| logger.info("Sending to subprocess...") | |
| proc.stdin.write(body) | |
| await proc.stdin.drain() | |
| # Read response | |
| response = bytearray() | |
| logger.info("Reading response...") | |
| while True: | |
| try: | |
| chunk = await proc.stdout.read(1024) | |
| if not chunk: | |
| logger.info("EOF reached") | |
| break | |
| response.extend(chunk) | |
| logger.debug("Received chunk: %s", chunk) | |
| # Check if we have a complete JSON message | |
| try: | |
| response_str = bytes(response).decode("utf-8") | |
| logger.debug("Decoded response: %s", response_str) | |
| # More robust JSON-RPC detection | |
| # Check if we have a complete JSON object | |
| if len(response_str.strip()) > 0: | |
| # Try to parse as JSON | |
| import json | |
| try: | |
| json_data = json.loads(response_str) | |
| # Check if it's a valid JSON-RPC response | |
| if isinstance(json_data, dict) and "jsonrpc" in json_data: | |
| # Check if it's a response (has id or error) | |
| if "id" in json_data or "error" in json_data: | |
| logger.info("Complete JSON-RPC response detected") | |
| break | |
| except json.JSONDecodeError as e: | |
| # If JSON parsing fails, continue reading | |
| logger.debug("JSON parsing failed: %s", str(e)) | |
| # Continue reading | |
| continue | |
| else: | |
| # Empty response, continue reading | |
| continue | |
| except Exception as e: | |
| logger.warning("Decoding failed: %s", str(e)) | |
| # Continue reading | |
| continue | |
| except Exception as e: | |
| logger.error("Error reading response: %s", str(e)) | |
| break | |
| # Log final response | |
| logger.info("Final response: %s", bytes(response).decode()) | |
| return Response(content=bytes(response)) | |
| async def shutdown_event(): | |
| if proc: | |
| logger.info("Shutting down subprocess...") | |
| proc.kill() | |
| await proc.wait() | |
| logger.info("Subprocess shut down") | |