Skip to main content
Glama
pyproject.toml9.09 kB
[project] name = "igloo_mcp" version = "0.4.1" description = "Igloo MCP - Snowflake MCP Server for agentic native workflows" readme = "README.md" authors = [ { name = "Evan Kim", email = "ekcopersonal@gmail.com" } ] requires-python = ">=3.12,<3.14" keywords = ["snowflake", "mcp", "ai", "data", "analytics", "model-context-protocol"] dependencies = [ "rich>=13.0.0", "pyyaml>=6.0.0", "snowflake-cli>=2.0.0", "sqlglot>=27.16.3", "pyjwt>=2.9.0", "pyvis>=0.3.2", "networkx>=3.0", "websockets>=15.0.1", "mcp>=1.0.0", "fastmcp>=2.8.1", "snowflake-labs-mcp>=1.3.3", "pydantic>=2.7.0", "jinja2>=3.1.0", "markdown>=3.5,<4.0", ] # MCP dependencies are included by default - no separate installation needed [project.scripts] # Primary entry point: MCP server for AI assistant integration igloo_mcp = "igloo_mcp.mcp_server:main" # Administrative entry point: CLI tools for power users and system administrators igloo = "igloo_mcp.cli:main" [project.urls] Homepage = "https://github.com/Evan-Kim2028/igloo-mcp" Repository = "https://github.com/Evan-Kim2028/igloo-mcp" Documentation = "https://github.com/Evan-Kim2028/igloo-mcp#readme" [build-system] requires = ["uv_build>=0.8.15,<0.9.0"] build-backend = "uv_build" [tool.uv] dev-dependencies = [ "pytest>=7.0.0", "pytest-asyncio>=0.21.0", "pytest-mock>=3.10.0", "pytest-xdist>=3.5.0", "ruff>=0.6.0", "mypy>=1.0.0", "pre-commit>=3.0.0", "types-pyyaml>=6.0.12.20250822", "inline-snapshot>=0.10.1", "dirty-equals>=0.7.0", "pytest-examples>=0.0.11", "types-networkx>=3.2.0.20240731", "pytest-cov>=7.0.0", "trio>=0.26.0", "hypothesis>=6.90.0", # Phase 2: Import linting "import-linter>=2.0", "types-markdown>=3.10.0.20251106", ] [tool.ruff] line-length = 120 target-version = "py312" [tool.ruff.lint] # Phase 1: Baseline + Security + Code Quality select = [ "E", # pycodestyle errors "F", # Pyflakes "I", # isort # Phase 1: Security "S", # flake8-bandit (security) "UP", # pyupgrade (modernize Python syntax) "SIM", # flake8-simplify "RUF", # Ruff-specific rules "B", # flake8-bugbear (bug detection) "C4", # flake8-comprehensions "PT", # flake8-pytest-style # Phase 2: Import organization "TID", # flake8-tidy-imports (ban relative imports) # v0.3.7: Exception handling "BLE", # flake8-blind-except (catch silent failures) ] ignore = [ "S101", # assert statements allowed in tests "S603", # subprocess without shell validation (manually validated) "S607", # partial executable path (manually validated) "B008", # function call in argument defaults (FastMCP pattern) ] [tool.ruff.lint.per-file-ignores] # Test files can use additional patterns "tests/**" = ["S101", "S105", "S106", "S108", "S301", "S608", "PT011", "PT012", "PT017", "B017"] # Best-effort operations that should not fail main workflow # These catch Exception for resilience but log warnings "src/igloo_mcp/cache/query_result_cache.py" = ["BLE001", "S110"] # Cache failures shouldn't break queries "src/igloo_mcp/logging/query_history.py" = ["BLE001", "S110"] # History logging is best-effort "src/igloo_mcp/cli.py" = ["BLE001"] # CLI should show user-friendly errors, not crash "src/igloo_mcp/living_reports/storage.py" = ["BLE001", "S110"] # File I/O failures logged but don't crash "src/igloo_mcp/error_handling.py" = ["BLE001"] # Error handling itself must be resilient "src/igloo_mcp/living_reports/service.py" = ["BLE001", "S110"] # Service layer has best-effort operations "src/igloo_mcp/catalog/catalog_service.py" = ["BLE001"] # Catalog operations are best-effort "src/igloo_mcp/dependency/dependency_service.py" = ["BLE001"] # Dependency graph is best-effort "src/igloo_mcp/living_reports/renderers/html_standalone.py" = ["BLE001"] # Chart embedding is best-effort "src/igloo_mcp/living_reports/index.py" = ["BLE001", "S110"] # Index operations are best-effort (already fixed #115 with logging) "src/igloo_mcp/mcp/tools/base.py" = ["BLE001"] # Tool error handling must be resilient "src/igloo_mcp/mcp/tools/build_catalog.py" = ["BLE001", "S110"] # Catalog building is best-effort "src/igloo_mcp/mcp/tools/evolve_report.py" = ["BLE001"] # Report evolution has best-effort validations "src/igloo_mcp/mcp/tools/execute_query.py" = ["S110", "B904", "SIM105", "BLE001"] # Query execution has resilient error paths # BLE001: lines 1024,1535 are legitimate broad catches "src/igloo_mcp/sql_validation.py" = ["BLE001", "S110"] # SQL parsing failures are expected fallback behavior "src/igloo_mcp/mcp/tools/get_catalog_summary.py" = ["BLE001", "S110"] # Catalog operations are best-effort "src/igloo_mcp/mcp/tools/health.py" = ["BLE001"] # Health checks are best-effort diagnostics "src/igloo_mcp/mcp/tools/render_report.py" = ["BLE001", "S110"] # Report rendering is best-effort "src/igloo_mcp/mcp/tools/search_catalog.py" = ["BLE001", "S110"] # Catalog search is best-effort "src/igloo_mcp/mcp/tools/search_citations.py" = ["BLE001"] # Citation search is best-effort "src/igloo_mcp/mcp/validation_helpers.py" = ["BLE001"] # Validation helpers have fallback behavior "src/igloo_mcp/mcp_health.py" = ["BLE001"] # Health monitoring is best-effort "src/igloo_mcp/mcp_resources.py" = ["BLE001"] # Resource loading is best-effort "src/igloo_mcp/mcp_server.py" = ["BLE001"] # Server lifecycle has resilient error handling # Phase 2: Ban relative parent imports (allow same-package imports) [tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "parents" [tool.ruff.format] # Like Black, use double quotes for strings quote-style = "double" # Like Black, indent with spaces, rather than tabs indent-style = "space" # Like Black, respect magic trailing commas skip-magic-trailing-comma = false # Like Black, automatically detect the appropriate line ending line-ending = "auto" [tool.pytest.ini_options] # Pytest configuration minversion = "7.0" testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] # Markers for test categorization markers = [ "requires_snowflake: marks tests requiring live Snowflake connection (skipped unless --snowflake)", "slow: marks tests as slow (deselect with '-m \"not slow\"')", "integration: marks integration tests (cross-component)", "system: marks system tests (end-to-end workflows)", "unit: marks unit tests (fast, isolated)", "performance: marks performance and scale tests", # Phase 3.6: Integration test categories "integration_catalog: marks catalog integration tests (build + search workflow)", "integration_reports: marks living reports integration tests (create + evolve + render)", "integration_query: marks query execution integration tests (execute + cache + history)", # Phase 3.6: System test categories "system_discovery: marks data discovery system tests (test → catalog → query)", "system_reporting: marks reporting system tests (create → evolve → search → render)", # Phase 3.6: Test quality markers "regression: marks regression tests for specific bug fixes", "property_based: marks property-based tests (Hypothesis)", ] # Default options (can override with CLI flags) addopts = [ "-ra", # Show summary of all test outcomes "--strict-markers", # Raise error on unknown markers "--strict-config", # Raise error on config issues "--showlocals", # Show local variables in tracebacks ] # Asyncio configuration asyncio_mode = "auto" [tool.coverage.run] # Coverage configuration source = ["src/igloo_mcp"] branch = true parallel = true omit = [ "*/tests/*", "*/test_*.py", "*/__pycache__/*", "*/site-packages/*", ] [tool.coverage.report] # Coverage reporting configuration precision = 2 show_missing = true skip_covered = false fail_under = 80 # Phase 3.6: Require 80% minimum coverage exclude_lines = [ "pragma: no cover", "def __repr__", "raise AssertionError", "raise NotImplementedError", "if __name__ == .__main__.:", "if TYPE_CHECKING:", "class .*\\bProtocol\\):", "@(abc\\.)?abstractmethod", ] [tool.coverage.html] directory = "htmlcov" [tool.coverage.json] output = "coverage.json" # Phase 2: Import-linter - Enforce layer architecture [tool.importlinter] root_packages = ["igloo_mcp"] # Layer architecture contract commented out due to shared descendants # We'll enforce via forbidden contracts instead # [[tool.importlinter.contracts]] # name = "Layer architecture" # type = "layers" # layers = [...] [[tool.importlinter.contracts]] name = "No circular dependencies between living_reports and mcp" type = "forbidden" source_modules = ["igloo_mcp.living_reports"] forbidden_modules = ["igloo_mcp.mcp.tools"] [[tool.importlinter.contracts]] name = "Service layer isolation" type = "independence" modules = [ "igloo_mcp.service_layer.catalog_service", "igloo_mcp.service_layer.query_service", "igloo_mcp.service_layer.dependency_service", ]

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Evan-Kim2028/igloo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server