fix(ci): fix black/ruff failures, add CoC and PR template
- Fix Python formatting (sync no longer strips blank lines from .py files) - Remove test_community_build.py (tests private sync module) - Fix ruff warnings in test files - Add CODE_OF_CONDUCT.md - Add .github/PULL_REQUEST_TEMPLATE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,7 @@ DCR_RATE_LIMIT_PER_MINUTE = int(os.getenv("DCR_RATE_LIMIT_PER_MINUTE", "10"))
|
||||
DCR_RATE_LIMIT_PER_HOUR = int(os.getenv("DCR_RATE_LIMIT_PER_HOUR", "30"))
|
||||
_dcr_rate_limits: dict = {}
|
||||
|
||||
|
||||
def is_redirect_uri_allowed_for_open_dcr(redirect_uris: list) -> bool:
|
||||
"""Check if all redirect_uris match the allowlist patterns."""
|
||||
for uri in redirect_uris:
|
||||
@@ -126,6 +127,7 @@ def is_redirect_uri_allowed_for_open_dcr(redirect_uris: list) -> bool:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def check_dcr_rate_limit(client_ip: str) -> tuple:
|
||||
"""Check if DCR request is within rate limits."""
|
||||
now = time.time()
|
||||
@@ -151,6 +153,7 @@ def check_dcr_rate_limit(client_ip: str) -> tuple:
|
||||
limits["hour"] += 1
|
||||
return True, ""
|
||||
|
||||
|
||||
# Initialize managers
|
||||
auth_manager = get_auth_manager()
|
||||
api_key_manager = get_api_key_manager()
|
||||
@@ -193,8 +196,10 @@ oauth_server = get_oauth_server()
|
||||
# Server start time
|
||||
server_start_time = time.time()
|
||||
|
||||
|
||||
# === TOOL GENERATION ===
|
||||
|
||||
|
||||
def generate_all_tools():
|
||||
"""Generate tools from all plugins into the tool registry"""
|
||||
logger.info("=" * 60)
|
||||
@@ -248,8 +253,10 @@ def generate_all_tools():
|
||||
logger.info(f"Total tools in registry: {tool_registry.get_count()}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
|
||||
# === ENDPOINT CREATION ===
|
||||
|
||||
|
||||
class EndpointAuthMiddleware(Middleware):
|
||||
"""Authentication middleware for specific endpoint"""
|
||||
|
||||
@@ -379,6 +386,7 @@ class EndpointAuthMiddleware(Middleware):
|
||||
logger.error(f"Auth error in {tool_name}: {e}")
|
||||
raise ToolError(f"Authentication error: {str(e)}")
|
||||
|
||||
|
||||
def create_dynamic_tool(
|
||||
name: str, description: str, handler: Callable, input_schema: dict | None = None
|
||||
) -> Callable:
|
||||
@@ -440,6 +448,7 @@ async def {name}({param_str}):
|
||||
|
||||
return dynamic_wrapper
|
||||
|
||||
|
||||
def get_tools_for_endpoint(config: EndpointConfig) -> list[ToolDefinition]:
|
||||
"""Get tools that should be registered for a specific endpoint"""
|
||||
tools = []
|
||||
@@ -472,6 +481,7 @@ def get_tools_for_endpoint(config: EndpointConfig) -> list[ToolDefinition]:
|
||||
|
||||
return tools
|
||||
|
||||
|
||||
def create_mcp_endpoint(config: EndpointConfig) -> FastMCP:
|
||||
"""Create a FastMCP instance for a specific endpoint"""
|
||||
mcp = FastMCP(config.name)
|
||||
@@ -496,8 +506,10 @@ def create_mcp_endpoint(config: EndpointConfig) -> FastMCP:
|
||||
|
||||
return mcp
|
||||
|
||||
|
||||
# === SYSTEM TOOLS (added to admin endpoint) ===
|
||||
|
||||
|
||||
def add_system_tools(mcp: FastMCP):
|
||||
"""Add system tools to an MCP instance"""
|
||||
|
||||
@@ -663,8 +675,10 @@ def add_system_tools(mcp: FastMCP):
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
# === HTTP ROUTES ===
|
||||
|
||||
|
||||
async def health_check(request: Request) -> JSONResponse:
|
||||
"""Health check endpoint"""
|
||||
return JSONResponse(
|
||||
@@ -678,6 +692,7 @@ async def health_check(request: Request) -> JSONResponse:
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def endpoint_info(request: Request) -> JSONResponse:
|
||||
"""List all available endpoints including per-project endpoints"""
|
||||
endpoints = []
|
||||
@@ -742,6 +757,7 @@ async def endpoint_info(request: Request) -> JSONResponse:
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# OAuth endpoints (imported from server.py patterns)
|
||||
async def oauth_metadata(request: Request) -> JSONResponse:
|
||||
"""OAuth 2.0 Authorization Server Metadata (RFC 8414)"""
|
||||
@@ -760,6 +776,7 @@ async def oauth_metadata(request: Request) -> JSONResponse:
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def oauth_protected_resource(request: Request) -> JSONResponse:
|
||||
"""OAuth 2.0 Protected Resource Metadata (RFC 9728)"""
|
||||
base_url = str(request.base_url).rstrip("/")
|
||||
@@ -772,6 +789,7 @@ async def oauth_protected_resource(request: Request) -> JSONResponse:
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def oauth_register(request: Request) -> JSONResponse:
|
||||
"""
|
||||
Dynamic Client Registration (RFC 7591) - MCP Spec Compliant
|
||||
@@ -865,6 +883,7 @@ async def oauth_register(request: Request) -> JSONResponse:
|
||||
logger.error(f"DCR error: {e}")
|
||||
return JSONResponse({"error": "server_error", "error_description": str(e)}, status_code=400)
|
||||
|
||||
|
||||
async def oauth_authorize(request: Request):
|
||||
"""OAuth Authorization Endpoint"""
|
||||
client_id = request.query_params.get("client_id")
|
||||
@@ -902,6 +921,7 @@ async def oauth_authorize(request: Request):
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def oauth_authorize_confirm(request: Request):
|
||||
"""Handle OAuth authorization form submission"""
|
||||
form = await request.form()
|
||||
@@ -941,6 +961,7 @@ async def oauth_authorize_confirm(request: Request):
|
||||
except Exception as e:
|
||||
return HTMLResponse(f"<h1>Error: {e}</h1>", status_code=400)
|
||||
|
||||
|
||||
async def oauth_token(request: Request) -> JSONResponse:
|
||||
"""OAuth Token Endpoint"""
|
||||
try:
|
||||
@@ -976,8 +997,10 @@ async def oauth_token(request: Request) -> JSONResponse:
|
||||
except Exception as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
# === MAIN APP CREATION ===
|
||||
|
||||
|
||||
def create_per_project_endpoints() -> dict[str, FastMCP]:
|
||||
"""
|
||||
Create per-project endpoints for each discovered site.
|
||||
@@ -1027,6 +1050,7 @@ def create_per_project_endpoints() -> dict[str, FastMCP]:
|
||||
logger.info(f"Created {len(project_endpoints)} per-project endpoints")
|
||||
return project_endpoints
|
||||
|
||||
|
||||
def create_app() -> Starlette:
|
||||
"""Create the main Starlette application with all endpoints"""
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
@@ -1103,8 +1127,10 @@ def create_app() -> Starlette:
|
||||
|
||||
return app
|
||||
|
||||
|
||||
# === ENTRY POINT ===
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
import argparse
|
||||
@@ -1127,5 +1153,6 @@ def main():
|
||||
|
||||
uvicorn.run(app, host=args.host, port=args.port, log_level="info")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user