[{'Text': 'Found 15 matches:\n\n## Matches in point-topic-mcp/src/point_topic_mcp/tools/gbs_tools.py\n\n### def list_operators › L24-34\n```\n    VALID_TYPES = ["broadband", "mobile", "iptv"]\n    VALID_CHANNELS = ["Infrastructure", "Retail"]\n    VALID_DOMAINS = ["Residential", "Business", "Total"]\n\n    def _valid_object_id(oid: str) -> bool:\n        """Check if string is valid 24-char hex ObjectId."""\n        if not oid or len(oid) != 24:\n            return False\n        return all(c in "0123456789abcdefABCDEF" for c in oid)\n\n    def list_operators(country: str = "", ctx=None) -> str:\n```\n\n357 lines remaining in ancestor node. Read the file to see all.\n\n### def list_operators › L35-45\n```\n        """\n        List ALL operators in the GBS database. Use before get_gbs_status to discover\n        valid operator names and IDs.\n\n        Always returns the complete, unfiltered list for the given country.\n        Use the country parameter to narrow results and prevent context overflow.\n\n        Args:\n            country: Optional filter by country (exact match, e.g. "United Kingdom").\n                     Leave empty for all operators.\n\n```\n\n4 lines remaining in ancestor node. Read the file to see all.\n\n### def get_gbs_status › L80-84\n```\n            return None\n\n    def get_gbs_status(\n        country: str,\n        operator: str,\n```\n\n### def add_statistic › L198-208\n```\n        """\n        Insert a Statistics (GBS) record with state: 1 (pending).\n\n        Operator name and country are auto-filled from the operator record to prevent mismatches.\n\n        Args:\n            type: broadband | mobile | iptv\n            operator_id: Operator ObjectId (from list_operators or get_gbs_status)\n            period: Quarter string (e.g. "2025Q1")\n            tech: Technology (must match operator\'s technologies)\n            channel: Infrastructure | Retail\n```\n\n10 lines remaining in ancestor node. Read the file to see all.\n\n### def create_source › L282-292\n```\n        """\n        Insert a Source record for an operator/period.\n\n        Args:\n            operator_id: Operator ObjectId (from list_operators or get_gbs_status)\n            year: Year (e.g. 2025)\n            quarter: Quarter 1-4\n            type: Source type (e.g. "report", "earnings_call", "tariff", "regulatory_filing")\n            url: Optional web page link — stored as-is in MongoDB ``url``\n            file_url: Optional file reference. Archived into ``pt-research-sources``; MongoDB\n                      ``fileUrl`` is always the permanent HTTPS URL there.\n```\n\n6 lines remaining in ancestor node. Read the file to see all.\n\n### def _run_test_flow › L395-413\n```\n    """Run GBS tools with real MongoDB. Use: uv run python -m point_topic_mcp.tools.gbs_tools"""\n    import re\n    import sys\n\n    mod_name = "point_topic_mcp.tools.gbs_tools"\n    gbs = sys.modules.get(mod_name) or sys.modules.get("__main__")\n    if not gbs or not hasattr(gbs, "list_operators"):\n        print("SKIP: GBS tools not loaded (PT_RESEARCH_DATABASE_URI not set)")\n        return\n\n    print("=== GBS Tools Test Flow ===\\n")\n\n    print("1. list_operators(country=\'United Kingdom\'):")\n    try:\n        out = gbs.list_operators(country="United Kingdom")\n        print(out)\n    except Exception as e:\n        print(f"   FAIL: {e}")\n        return\n```\n\n82 lines remaining in ancestor node. Read the file to see all.\n\n### def _run_test_flow › L439-446\n```\n            break\n\n    print(f"\\n2. get_gbs_status(\'{country}\', \'{op_name}\', \'2025Q1\'):")\n    try:\n        status = gbs.get_gbs_status(country, op_name, "2025Q1")\n        print(status[:800] + ("..." if len(status) > 800 else ""))\n    except Exception as e:\n        print(f"   FAIL: {e}")\n```\n\n## Matches in point-topic-mcp/src/point_topic_mcp/tools/server_info_tools.py\n\n### def get_mcp_server_capabilities › L67-71\n```\n    • SNOWFLAKE_USER + SNOWFLAKE_PASSWORD → Database tools (execute_query, assemble_dataset_context, etc.)\n    • GITHUB_TOKEN → GitHub organization tools (search_issues_across_org, create_issue, etc.)\n    • PT_RESEARCH_DATABASE_URI → GBS tools (list_operators, get_gbs_status, add_statistic, create_source)\n    • CHART_API_KEY → Authenticated chart generation (generate_authenticated_chart_url)\n    • Public chart tools available without credentials (get_point_topic_public_chart_catalog)\n```\n\n## Matches in point-topic-mcp/tests/test_gbs_tools.py\n\n### def test_list_operators › L125-136\n```\ndef test_list_operators():\n    """list_operators returns all operators sorted by name."""\n    from bson import ObjectId\n\n    import point_topic_mcp.tools.gbs_tools as gbs\n\n    if not hasattr(gbs, "list_operators"):\n        pytest.skip("GBS tools not loaded (PT_RESEARCH_DATABASE_URI not set)")\n\n    op_id_a = ObjectId()\n    op_id_b = ObjectId()\n    op_id_c = ObjectId()\n```\n\n23 lines remaining in ancestor node. Read the file to see all.\n\n### def test_list_operators › L144-154\n```\n    with patch("point_topic_mcp.core.mongodb_utils.find_operators", return_value=mock_ops):\n        # Test 1: basic call, should be sorted\n        result = gbs.list_operators()\n        assert "Operators:" in result\n        assert "Alpha" in result\n        assert "Beta" in result\n        assert "Zebra" in result\n        # Check ordering: Alpha should appear before Beta, Beta before Zebra\n        alpha_pos = result.find("Alpha")\n        beta_pos = result.find("Beta")\n        zebra_pos = result.find("Zebra")\n```\n\n5 lines remaining in ancestor node. Read the file to see all.\n\n### def test_list_operators › L156-160\n```\n        \n        # Test 2: with country filter\n        result_filtered = gbs.list_operators(country="UK")\n        assert "(country filter: \'UK\', 3 match(es))" in result_filtered\n\n```\n\n### def test_get_gbs_status_operator_not_found › L162-171\n```\ndef test_get_gbs_status_operator_not_found():\n    """get_gbs_status returns error when operator doesn\'t exist."""\n    import point_topic_mcp.tools.gbs_tools as gbs\n\n    if not hasattr(gbs, "get_gbs_status"):\n        pytest.skip("GBS tools not loaded (PT_RESEARCH_DATABASE_URI not set)")\n\n    with patch("point_topic_mcp.core.mongodb_utils.find_one_operator", return_value=None):\n        result = gbs.get_gbs_status("UK", "NoSuchOperator", "2025Q1")\n        assert "Operator not found" in result\n```\n\n### def test_get_gbs_status_success › L174-185\n```\ndef test_get_gbs_status_success():\n    """get_gbs_status returns status with operator_id, gaps grouped by type, staleness."""\n    from bson import ObjectId\n\n    import point_topic_mcp.tools.gbs_tools as gbs\n\n    if not hasattr(gbs, "get_gbs_status"):\n        pytest.skip("GBS tools not loaded (PT_RESEARCH_DATABASE_URI not set)")\n\n    op_id = ObjectId()\n    mock_op = {"_id": {"$oid": str(op_id)}, "name": "BT", "country": "UK", "technologies": ["FTTP", "FTTC"]}\n    mock_stats = [{"type": "broadband", "tech": "FTTP", "channel": "Infrastructure", "domain": "Residential", "state": 1}]\n```\n\n27 lines remaining in ancestor node. Read the file to see all.\n\n### def test_get_gbs_status_success › L187-197\n```\n    with (\n        patch("point_topic_mcp.core.mongodb_utils.find_one_operator", return_value=mock_op),\n        patch("point_topic_mcp.core.mongodb_utils.find_statistics", return_value=mock_stats),\n        patch("point_topic_mcp.core.mongodb_utils.find_global_variables_current", return_value=mock_gv),\n    ):\n        result = gbs.get_gbs_status("UK", "BT", "2025Q1")\n        assert "GBS status: BT (UK)" in result\n        assert "operator_id: " + str(op_id) in result\n        assert "technologies: FTTP, FTTC" in result\n        assert "Existing: 1 records" in result\n        assert "by type: broadband: 1" in result\n```\n\n5 lines remaining in ancestor node. Read the file to see all.\n\n### def test_get_gbs_status_success › L206-212\n```\n    with (\n        patch("point_topic_mcp.core.mongodb_utils.find_one_operator", return_value=mock_op),\n        patch("point_topic_mcp.core.mongodb_utils.find_statistics", return_value=[]),\n        patch("point_topic_mcp.core.mongodb_utils.find_global_variables_current", return_value=mock_gv_ahead),\n    ):\n        result2 = gbs.get_gbs_status("UK", "BT", "2025Q1")\n        assert "2 quarters behind current (2025Q3)" in result2\n```\n'}]