diff --git a/mcp_server/.env.example b/mcp_server/.env.example index dd4677b29..a115a7be1 100644 --- a/mcp_server/.env.example +++ b/mcp_server/.env.example @@ -31,6 +31,11 @@ MODEL_NAME=gpt-4.1-mini # See README.md "Concurrency and LLM Provider 429 Rate Limit Errors" for details SEMAPHORE_LIMIT=10 +# MCP server logging level (default: INFO) +# Controls verbosity of Graphiti MCP server logs only +# Valid values: DEBUG, INFO, WARNING, ERROR, CRITICAL +LOG_LEVEL=INFO + # Optional: Path configuration for Docker # PATH=/root/.local/bin:${PATH} diff --git a/mcp_server/README.md b/mcp_server/README.md index b1bca95b7..ce99ca89d 100644 --- a/mcp_server/README.md +++ b/mcp_server/README.md @@ -238,6 +238,7 @@ The `config.yaml` file supports environment variable expansion using `${VAR_NAME - `AZURE_OPENAI_API_VERSION`: Optional Azure OpenAI API version - `USE_AZURE_AD`: Optional use Azure Managed Identities for authentication - `SEMAPHORE_LIMIT`: Episode processing concurrency. See [Concurrency and LLM Provider 429 Rate Limit Errors](#concurrency-and-llm-provider-429-rate-limit-errors) +- `LOG_LEVEL`: MCP server logging verbosity (default: `INFO`). Valid values: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` You can set these variables in a `.env` file in the project directory. diff --git a/mcp_server/src/graphiti_mcp_server.py b/mcp_server/src/graphiti_mcp_server.py index 833bc5d93..4a5650eb3 100644 --- a/mcp_server/src/graphiti_mcp_server.py +++ b/mcp_server/src/graphiti_mcp_server.py @@ -79,8 +79,12 @@ LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' DATE_FORMAT = '%Y-%m-%d %H:%M:%S' +# Log level from environment variable (default: INFO) +# Valid values: DEBUG, INFO, WARNING, ERROR, CRITICAL +LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO').upper() + logging.basicConfig( - level=logging.INFO, + level=getattr(logging, LOG_LEVEL, logging.INFO), format=LOG_FORMAT, datefmt=DATE_FORMAT, stream=sys.stderr, diff --git a/mcp_server/tests/test_configuration.py b/mcp_server/tests/test_configuration.py index 5876c1ed4..b937cb36a 100644 --- a/mcp_server/tests/test_configuration.py +++ b/mcp_server/tests/test_configuration.py @@ -48,6 +48,41 @@ def test_config_loading(): return config +def test_log_level_environment_variable(): + """Test LOG_LEVEL environment variable configuration for MCP server.""" + import logging + + print('\nTesting LOG_LEVEL environment variable...') + + # Test default (INFO) + if 'LOG_LEVEL' in os.environ: + del os.environ['LOG_LEVEL'] + log_level = os.getenv('LOG_LEVEL', 'INFO').upper() + assert getattr(logging, log_level, logging.INFO) == logging.INFO + print('✓ Default LOG_LEVEL is INFO') + + # Test DEBUG override + os.environ['LOG_LEVEL'] = 'DEBUG' + log_level = os.getenv('LOG_LEVEL', 'INFO').upper() + assert getattr(logging, log_level, logging.INFO) == logging.DEBUG + print('✓ LOG_LEVEL=DEBUG works correctly') + del os.environ['LOG_LEVEL'] + + # Test invalid value falls back to INFO + os.environ['LOG_LEVEL'] = 'INVALID' + log_level = os.getenv('LOG_LEVEL', 'INFO').upper() + assert getattr(logging, log_level, logging.INFO) == logging.INFO + print('✓ Invalid LOG_LEVEL falls back to INFO') + del os.environ['LOG_LEVEL'] + + # Test case insensitivity + os.environ['LOG_LEVEL'] = 'warning' + log_level = os.getenv('LOG_LEVEL', 'INFO').upper() + assert getattr(logging, log_level, logging.INFO) == logging.WARNING + print('✓ LOG_LEVEL is case-insensitive') + del os.environ['LOG_LEVEL'] + + def test_llm_factory(config: GraphitiConfig): """Test LLM client factory creation.""" print('\nTesting LLM client factory...') @@ -186,6 +221,9 @@ async def main(): # Test configuration loading config = test_config_loading() + # Test LOG_LEVEL environment variable + test_log_level_environment_variable() + # Test factories test_llm_factory(config) test_embedder_factory(config)