quick fix
This commit is contained in:
@@ -57,7 +57,13 @@ TOOL_HANDLERS = {
|
|||||||
# Authentication middleware
|
# Authentication middleware
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
async def authenticate_request(request: Request, call_next):
|
async def authenticate_request(request: Request, call_next):
|
||||||
"""Authenticate all requests except health checks and root."""
|
"""Authenticate all requests except health checks and root.
|
||||||
|
|
||||||
|
Supports Mixed authentication mode where:
|
||||||
|
- /mcp/tools (list tools) is publicly accessible (No Auth)
|
||||||
|
- /mcp/tool/call (execute tools) requires authentication
|
||||||
|
- /mcp/sse requires authentication
|
||||||
|
"""
|
||||||
# Skip authentication for health check and root endpoints
|
# Skip authentication for health check and root endpoints
|
||||||
if request.url.path in ["/", "/health"]:
|
if request.url.path in ["/", "/health"]:
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
@@ -66,6 +72,10 @@ async def authenticate_request(request: Request, call_next):
|
|||||||
if not request.url.path.startswith("/mcp/"):
|
if not request.url.path.startswith("/mcp/"):
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
|
# Mixed mode: allow /mcp/tools without authentication (for ChatGPT discovery)
|
||||||
|
if request.url.path == "/mcp/tools":
|
||||||
|
return await call_next(request)
|
||||||
|
|
||||||
# Extract client information
|
# Extract client information
|
||||||
client_ip = request.client.host if request.client else "unknown"
|
client_ip = request.client.host if request.client else "unknown"
|
||||||
user_agent = request.headers.get("user-agent", "unknown")
|
user_agent = request.headers.get("user-agent", "unknown")
|
||||||
@@ -75,7 +85,7 @@ async def authenticate_request(request: Request, call_next):
|
|||||||
api_key = auth_validator.extract_bearer_token(auth_header)
|
api_key = auth_validator.extract_bearer_token(auth_header)
|
||||||
|
|
||||||
# Fallback: allow API key via query parameter only for MCP endpoints
|
# Fallback: allow API key via query parameter only for MCP endpoints
|
||||||
if not api_key and request.url.path in {"/mcp/tools", "/mcp/tool/call", "/mcp/sse"}:
|
if not api_key and request.url.path in {"/mcp/tool/call", "/mcp/sse"}:
|
||||||
api_key = request.query_params.get("api_key")
|
api_key = request.query_params.get("api_key")
|
||||||
|
|
||||||
# Validate API key
|
# Validate API key
|
||||||
@@ -105,14 +115,14 @@ async def startup_event() -> None:
|
|||||||
logger.info(f"Starting AegisGitea MCP Server on {settings.mcp_host}:{settings.mcp_port}")
|
logger.info(f"Starting AegisGitea MCP Server on {settings.mcp_host}:{settings.mcp_port}")
|
||||||
logger.info(f"Connected to Gitea instance: {settings.gitea_base_url}")
|
logger.info(f"Connected to Gitea instance: {settings.gitea_base_url}")
|
||||||
logger.info(f"Audit logging enabled: {settings.audit_log_path}")
|
logger.info(f"Audit logging enabled: {settings.audit_log_path}")
|
||||||
|
|
||||||
# Log authentication status
|
# Log authentication status
|
||||||
if settings.auth_enabled:
|
if settings.auth_enabled:
|
||||||
key_count = len(settings.mcp_api_keys)
|
key_count = len(settings.mcp_api_keys)
|
||||||
logger.info(f"API key authentication ENABLED ({key_count} key(s) configured)")
|
logger.info(f"API key authentication ENABLED ({key_count} key(s) configured)")
|
||||||
else:
|
else:
|
||||||
logger.warning("API key authentication DISABLED - server is open to all requests!")
|
logger.warning("API key authentication DISABLED - server is open to all requests!")
|
||||||
|
|
||||||
# Test Gitea connection
|
# Test Gitea connection
|
||||||
try:
|
try:
|
||||||
async with GiteaClient() as gitea:
|
async with GiteaClient() as gitea:
|
||||||
@@ -249,6 +259,7 @@ async def sse_endpoint(request: Request) -> StreamingResponse:
|
|||||||
Returns:
|
Returns:
|
||||||
Streaming SSE response
|
Streaming SSE response
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def event_stream():
|
async def event_stream():
|
||||||
"""Generate SSE events."""
|
"""Generate SSE events."""
|
||||||
# Send initial connection event
|
# Send initial connection event
|
||||||
@@ -259,14 +270,15 @@ async def sse_endpoint(request: Request) -> StreamingResponse:
|
|||||||
while True:
|
while True:
|
||||||
if await request.is_disconnected():
|
if await request.is_disconnected():
|
||||||
break
|
break
|
||||||
|
|
||||||
# Heartbeat every 30 seconds
|
# Heartbeat every 30 seconds
|
||||||
yield f"data: {{'event': 'heartbeat'}}\n\n"
|
yield f"data: {{'event': 'heartbeat'}}\n\n"
|
||||||
|
|
||||||
# Wait for next heartbeat (in production, this would handle actual events)
|
# Wait for next heartbeat (in production, this would handle actual events)
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
await asyncio.sleep(30)
|
await asyncio.sleep(30)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"SSE stream error: {e}")
|
logger.error(f"SSE stream error: {e}")
|
||||||
|
|
||||||
@@ -286,7 +298,7 @@ def main() -> None:
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"aegis_gitea_mcp.server:app",
|
"aegis_gitea_mcp.server:app",
|
||||||
host=settings.mcp_host,
|
host=settings.mcp_host,
|
||||||
|
|||||||
Reference in New Issue
Block a user