@@ -395,74 +395,59 @@ class ConfigSchema(BaseModel):
395395
396396def get_api_key (ctx : Context ) -> str :
397397 """
398- Get the API key from config or environment variable.
399-
398+ Get the API key from HTTP header or MCP session config.
399+
400+ Supports two modes:
401+ - HTTP mode (Render): API key from 'X-API-Key' header via mcp-remote
402+ - Stdio mode (Smithery): API key from session_config.scrapegraph_api_key
403+
400404 Args:
401405 ctx: FastMCP context
402-
406+
403407 Returns:
404408 API key string
405-
409+
406410 Raises:
407411 ValueError: If no API key is found
408412 """
413+ from fastmcp .server .dependencies import get_http_headers
414+
415+ # Try HTTP header first (for remote/Render deployments)
409416 try :
410- logger .info (f"Getting API key. Context type: { type (ctx )} " )
411- logger .info (f"Context has session_config: { hasattr (ctx , 'session_config' )} " )
412-
413- # Try to get from config first, but handle cases where session_config might be None
414- api_key = None
415- if hasattr (ctx , 'session_config' ) and ctx .session_config is not None :
416- logger .info (f"Session config type: { type (ctx .session_config )} " )
417- api_key = getattr (ctx .session_config , 'scrapegraph_api_key' , None )
418- logger .info (f"API key from config: { '***' if api_key else 'None' } " )
419- else :
420- logger .info ("No session_config available or session_config is None" )
421-
422- # If not in config, try environment variable
423- if not api_key :
424- api_key = os .getenv ('SGAI_API_KEY' )
425- logger .info (f"API key from env: { '***' if api_key else 'None' } " )
426-
427- # If still no API key found, raise error
428- if not api_key :
429- logger .error ("No API key found in config or environment" )
430- raise ValueError (
431- "ScapeGraph API key is required. Please provide it either:\n "
432- "1. In the MCP server configuration as 'scrapegraph_api_key'\n "
433- "2. As an environment variable 'SGAI_API_KEY'"
434- )
435-
436- logger .info ("API key successfully retrieved" )
437- return api_key
438-
439- except Exception as e :
440- logger .warning (f"Error getting API key from context: { e } . Falling back to cached method." )
441- # Fallback to cached method if context handling fails
442- return get_cached_api_key ()
417+ headers = get_http_headers ()
418+ api_key = headers .get ('x-api-key' )
419+ if api_key :
420+ logger .info ("API key retrieved from X-API-Key header" )
421+ return api_key
422+ except LookupError :
423+ # Not in HTTP context, try session config (Smithery/stdio mode)
424+ pass
425+
426+ # Try session config (for Smithery/stdio deployments)
427+ if hasattr (ctx , 'session_config' ) and ctx .session_config is not None :
428+ api_key = getattr (ctx .session_config , 'scrapegraph_api_key' , None )
429+ if api_key :
430+ logger .info ("API key retrieved from session config" )
431+ return api_key
432+
433+ logger .error ("No API key found in header or session config" )
434+ raise ValueError (
435+ "ScapeGraph API key is required. Please provide it via:\n "
436+ "- HTTP header 'X-API-Key' (for remote server via mcp-remote)\n "
437+ "- MCP config 'scrapegraphApiKey' (for Smithery/local stdio)"
438+ )
443439
444440
445441# Create MCP server instance
446442mcp = FastMCP ("ScapeGraph API MCP Server" )
447443
448- # Global API key cache to handle session issues
449- _api_key_cache : Optional [str ] = None
450444
451- def get_cached_api_key () -> str :
452- """Get API key from cache or environment, bypassing session config issues."""
453- global _api_key_cache
454-
455- if _api_key_cache is None :
456- _api_key_cache = os .getenv ('SGAI_API_KEY' )
457- if _api_key_cache :
458- logger .info ("API key loaded from environment variable" )
459- else :
460- logger .error ("No API key found in environment variable SGAI_API_KEY" )
461- raise ValueError (
462- "ScapeGraph API key is required. Please set the SGAI_API_KEY environment variable."
463- )
464-
465- return _api_key_cache
445+ # Health check endpoint for remote deployments (Render, etc.)
446+ @mcp .custom_route ("/health" , methods = ["GET" ])
447+ async def health_check (request ):
448+ """Health check endpoint for container orchestration and load balancers."""
449+ from starlette .responses import JSONResponse
450+ return JSONResponse ({"status" : "healthy" , "service" : "scrapegraph-mcp" })
466451
467452
468453# Add prompts to help users interact with the server
@@ -2298,13 +2283,30 @@ def create_server() -> FastMCP:
22982283
22992284
23002285def main () -> None :
2301- """Run the ScapeGraph MCP server."""
2286+ """Run the ScapeGraph MCP server.
2287+
2288+ Supports two transport modes:
2289+ - stdio (default): For local use with Claude Desktop, Cursor, etc.
2290+ - http: For remote deployment on Render, Koyeb, etc.
2291+
2292+ Set MCP_TRANSPORT=http environment variable for remote deployment.
2293+ """
2294+ transport = os .getenv ("MCP_TRANSPORT" , "stdio" ).lower ()
2295+
23022296 try :
2303- # Verify we're running from local codebase
2304- server_path = os .path .abspath (__file__ )
2305- logger .info (f"Starting ScapeGraph MCP server from local codebase: { server_path } " )
2306- print (f"Starting ScapeGraph MCP server (local codebase)" )
2307- mcp .run (transport = "stdio" )
2297+ if transport == "http" :
2298+ # Remote deployment mode (Render, Koyeb, etc.)
2299+ host = os .getenv ("HOST" , "0.0.0.0" )
2300+ port = int (os .getenv ("PORT" , "8000" ))
2301+ logger .info (f"Starting ScapeGraph MCP server in HTTP mode on { host } :{ port } " )
2302+ print (f"Starting ScapeGraph MCP server in HTTP mode on { host } :{ port } " )
2303+ mcp .run (transport = "http" , host = host , port = port )
2304+ else :
2305+ # Local stdio mode (Claude Desktop, Cursor, etc.)
2306+ server_path = os .path .abspath (__file__ )
2307+ logger .info (f"Starting ScapeGraph MCP server from local codebase: { server_path } " )
2308+ print ("Starting ScapeGraph MCP server (local codebase)" )
2309+ mcp .run (transport = "stdio" )
23082310 except Exception as e :
23092311 logger .error (f"Failed to start MCP server: { e } " )
23102312 print (f"Error starting server: { e } " )
0 commit comments