[{'Text': '"""GBS (Global Broadband Statistics) tools for PT Research App.\n\nMongoDB utils for Statistics and Sources. Used by PT Systems Agent for\nhuman-supervised GBS data entry (see upc_query_agent issue #37).\n\nUses mongosh (shell) instead of PyMongo - avoids Python SSL issues in\ncloud/EC2 environments. Requires mongosh installed on the host.\n\nRef: pt-research-app schema (Statistics, Sources)\n"""\n\nfrom typing import Optional\n\nfrom point_topic_mcp.core.utils import check_env_vars\nfrom point_topic_mcp.core import mongodb_utils as mongo\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\n# GBS tools require PT Research App MongoDB connection\nif check_env_vars("gbs_tools", ["PT_RESEARCH_DATABASE_URI"]):\n\n    # Valid enums from pt-research-app\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 = "", limit: int = 0, ctx=None) -> str:\n        """\n        List operators in the GBS database. Use before get_gbs_status to discover\n        valid operator names and IDs.\n\n        Args:\n            country: Optional filter by country (exact match, e.g. "United Kingdom"). Leave empty for all.\n            limit: Max operators to return. 0 = no limit. Useful to prevent context explosion.\n\n        Returns:\n            List of operators sorted by name, with name, country, operator_id (use in add_statistic/create_source).\n        """\n        ops = mongo.find_operators(country)\n        \n        if not ops:\n            return f"No operators found" + (f" for country \'{country}\'" if country else "")\n        \n        # Sort by name (case-insensitive) for stable, predictable order\n        ops_sorted = sorted(ops, key=lambda o: o.get("name", "").lower())\n        \n        # Warn on context explosion if no country filter and many operators\n        if not country and len(ops_sorted) > 400:\n            warning = f"⚠ WARNING: {len(ops_sorted)} operators total. Pass country filter or limit to prevent context overflow.\\n\\n"\n        else:\n            warning = ""\n        \n        # Build rows, optionally limited\n        rows = []\n        for op in ops_sorted[:limit] if limit > 0 else ops_sorted:\n            oid = mongo._oid_from_doc(op)\n            name = op.get("name", "?")\n            c = op.get("country", "?")\n            techs = op.get("technologies", [])\n            rows.append(f"  {name} | {c} | id={oid} | techs={techs}")\n        \n        # Header showing filter applied\n        filter_header = ""\n        if country:\n            filter_header = f"(country filter: \'{country}\', {len(ops_sorted)} match(es))\\n"\n        \n        # Pagination footer if limited\n        footer = ""\n        if limit > 0 and len(ops_sorted) > limit:\n            footer = f"\\n... showing {limit} of {len(ops_sorted)} operators"\n        \n        return warning + filter_header + "Operators:\\n" + "\\n".join(rows) + footer\n\n'}]