#!/usr/bin/env python3 """FastAPI mock server for debugging proxy/client behavior. This is a development helper (not used by the main KiroProxy app). Typical usage: python scripts/proxy_server.py --port 8000 Then point your client/proxy to `http://127.0.0.1:8000` and inspect requests: GET http://127.0.0.1:8000/logs """ from __future__ import annotations import argparse import json import logging from datetime import datetime from typing import Any, Dict, List import uvicorn from fastapi import FastAPI, Request from fastapi.responses import JSONResponse logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger("kiro_proxy.mock_server") app = FastAPI(title="KiroProxy Mock Server") request_log: List[Dict[str, Any]] = [] @app.middleware("http") async def log_requests(request: Request, call_next): body = await request.body() request_log.append( { "timestamp": datetime.now().isoformat(), "method": request.method, "url": str(request.url), "path": request.url.path, "headers": dict(request.headers), "body": body.decode("utf-8", errors="ignore")[:2000] if body else None, } ) logger.info("%s %s", request.method, request.url.path) return await call_next(request) @app.get("/") async def root(): return {"status": "ok", "message": "Mock server running", "requests_logged": len(request_log)} @app.get("/logs") async def get_logs(limit: int = 50): return {"total": len(request_log), "requests": request_log[-limit:]} @app.get("/clear") async def clear_logs(): request_log.clear() return {"message": "Logs cleared"} @app.api_route("/auth/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]) async def mock_auth(_: Request, path: str): logger.info("Auth request: %s", path) return JSONResponse({"success": True, "token": "mock-token-for-testing", "expires_in": 3600}) @app.post("/v1/chat/completions") async def mock_chat_completions(request: Request): body = await request.json() logger.info("Chat body preview: %s", json.dumps(body, ensure_ascii=False)[:500]) return JSONResponse( { "id": "chatcmpl-test", "object": "chat.completion", "created": int(datetime.now().timestamp()), "model": body.get("model", "mock-model"), "choices": [ { "index": 0, "message": {"role": "assistant", "content": "Mock response from scripts/proxy_server.py"}, "finish_reason": "stop", } ], "usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30}, } ) @app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]) async def catch_all(request: Request, path: str): logger.info("Caught: %s /%s", request.method, path) return JSONResponse( { "proxy_status": "intercepted", "method": request.method, "path": f"/{path}", "message": "Request intercepted by mock server", "headers_received": dict(request.headers), } ) def _parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="KiroProxy mock server (dev helper)") parser.add_argument("--host", default="0.0.0.0", help="Bind host") parser.add_argument("--port", type=int, default=8000, help="Bind port") return parser.parse_args() if __name__ == "__main__": args = _parse_args() uvicorn.run(app, host=args.host, port=args.port)