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") | |
| if not token: | |
| logger.error("GITHUB_PERSONAL_ACCESS_TOKEN environment variable not set") | |
| return | |
| logger.info("Starting subprocess with token: %s", token[:10] + "...") | |
| 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 started with PID: %s", proc.pid) | |
| asyncio.create_task(log_stderr()) | |
| async def log_stderr(): | |
| if proc and proc.stderr: | |
| while not proc.stderr.at_eof(): | |
| line = await proc.stderr.readline() | |
| logger.debug("github-mcp-server stderr: %s", line.decode().strip()) | |
| 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()) | |
| # 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) | |
| # If we can decode and it looks like a complete JSON-RPC response, break | |
| if response_str.strip().endswith("}") and "\"jsonrpc\"" in response_str and "\"result\"" in response_str: | |
| logger.info("Complete JSON-RPC response detected") | |
| break | |
| except Exception as e: | |
| logger.warning("Decoding failed: %s", str(e)) | |
| # Continue reading | |
| 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") |