@@ -117,9 +117,7 @@ def _attached_db_schema(db_name: str, build_hint: str) -> str:
117117 count = conn .execute (f"SELECT COUNT(*) FROM { db_name } .[{ t ['name' ]} ]" ).fetchone ()[0 ]
118118 lines .append (f"-- { t ['name' ]} : { count :,} rows" )
119119 lines .append (t ["sql" ] + ";\n " )
120- views = conn .execute (
121- f"SELECT name, sql FROM { db_name } .sqlite_master WHERE type='view' ORDER BY name"
122- ).fetchall ()
120+ views = conn .execute (f"SELECT name, sql FROM { db_name } .sqlite_master WHERE type='view' ORDER BY name" ).fetchall ()
123121 if views :
124122 lines .append (f"\n -- { db_name .upper ()} VIEWS\n " )
125123 for v in views :
@@ -795,9 +793,7 @@ def cloud_pricing_lookup(
795793 """
796794 conn = _get_conn ()
797795 if not _db_attached (conn , "pricing" ):
798- return json .dumps (
799- {"error" : "pricing.db not attached. Run: uv run scripts/fetch_pricing.py" }
800- )
796+ return json .dumps ({"error" : "pricing.db not attached. Run: uv run scripts/fetch_pricing.py" })
801797
802798 if not any ([provider , service , instance_type , region , model_name , usage_type ]):
803799 return json .dumps ({"error" : "Provide at least one filter" })
@@ -850,17 +846,11 @@ def rosa_cluster_costs() -> str:
850846 """
851847 conn = _get_conn ()
852848 if not _db_attached (conn , "pricing" ):
853- return json .dumps (
854- {"error" : "pricing.db not attached. Run: uv run scripts/fetch_pricing.py" }
855- )
849+ return json .dumps ({"error" : "pricing.db not attached. Run: uv run scripts/fetch_pricing.py" })
856850
857- rows = conn .execute (
858- "SELECT * FROM pricing.v_rosa_estimated_cost ORDER BY estimated_monthly_cost DESC"
859- ).fetchall ()
851+ rows = conn .execute ("SELECT * FROM pricing.v_rosa_estimated_cost ORDER BY estimated_monthly_cost DESC" ).fetchall ()
860852 if not rows :
861- return json .dumps (
862- {"error" : "No ROSA cluster data. Run: uv run scripts/fetch_pricing.py (requires oc access)" }
863- )
853+ return json .dumps ({"error" : "No ROSA cluster data. Run: uv run scripts/fetch_pricing.py (requires oc access)" })
864854 return json .dumps ({"clusters" : _rows_to_dicts (rows ), "count" : len (rows )}, default = str )
865855
866856
@@ -879,9 +869,7 @@ def github_org_summary() -> str:
879869 """
880870 conn = _get_conn ()
881871 if not _db_attached (conn , "github" ):
882- return json .dumps (
883- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
884- )
872+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
885873
886874 stats = conn .execute ("SELECT * FROM github.v_gh_org_stats" ).fetchone ()
887875 result = dict (stats )
@@ -913,20 +901,21 @@ def search_github_repos(
913901 name : str | None = None ,
914902 language : str | None = None ,
915903 topic : str | None = None ,
904+ limit : int = 50 ,
916905) -> str :
917906 """Search GitHub repos by name, language, or topic. All filters are partial match.
918907
919908 Provide at least one parameter. Returns repo details with language breakdown.
909+ Returns up to `limit` repos (default 50, max 200).
920910 """
921911 if not any ([name , language , topic ]):
922912 return json .dumps ({"error" : "Provide at least one of: name, language, topic" })
923913
924914 conn = _get_conn ()
925915 if not _db_attached (conn , "github" ):
926- return json .dumps (
927- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
928- )
916+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
929917
918+ limit = min (limit , MAX_QUERY_ROWS )
930919 conditions , params = [], []
931920 if name :
932921 conditions .append ("r.name LIKE ?" )
@@ -944,28 +933,35 @@ def search_github_repos(
944933
945934 where = " AND " .join (conditions )
946935 repos = conn .execute (
947- f"""SELECT r.name, r.description, r.html_url, r.default_branch,
936+ f"""SELECT r.repo_id, r. name, r.description, r.html_url, r.default_branch,
948937 r.is_fork, r.is_archived, r.stars, r.forks, r.open_issues,
949938 r.size_kb, r.created_at, r.pushed_at,
950939 r.commit_count, r.pr_count, r.merged_pr_count, r.issue_count,
951940 r.contributor_count, r.topics, r.total_language_bytes
952941 FROM github.v_gh_repo_summary r
953942 WHERE { where }
954- ORDER BY r.commit_count DESC""" ,
955- params ,
943+ ORDER BY r.commit_count DESC
944+ LIMIT ?""" ,
945+ [* params , limit ],
956946 ).fetchall ()
957947
948+ # Batch-load languages for all repos to avoid N+1 queries
949+ repo_ids = [repo ["repo_id" ] for repo in repos ]
950+ langs_by_repo : dict [int , list [dict ]] = {}
951+ if repo_ids :
952+ ph = "," .join ("?" * len (repo_ids ))
953+ lang_rows = conn .execute (
954+ f"SELECT repo_id, language, bytes FROM github.gh_repo_language WHERE repo_id IN ({ ph } ) ORDER BY bytes DESC" ,
955+ repo_ids ,
956+ ).fetchall ()
957+ for lr in lang_rows :
958+ langs_by_repo .setdefault (lr ["repo_id" ], []).append ({"language" : lr ["language" ], "bytes" : lr ["bytes" ]})
959+
958960 results = []
959961 for repo in repos :
960962 r = dict (repo )
961- # Add language breakdown
962- langs = conn .execute (
963- "SELECT language, bytes FROM github.gh_repo_language "
964- "WHERE repo_id = (SELECT repo_id FROM github.gh_repo WHERE name = ?) "
965- "ORDER BY bytes DESC" ,
966- (r ["name" ],),
967- ).fetchall ()
968- r ["languages" ] = _rows_to_dicts (langs )
963+ rid = r .pop ("repo_id" )
964+ r ["languages" ] = langs_by_repo .get (rid , [])
969965 results .append (r )
970966
971967 return json .dumps ({"repos" : results , "count" : len (results )}, default = str )
@@ -991,9 +987,7 @@ def search_github_commits(
991987
992988 conn = _get_conn ()
993989 if not _db_attached (conn , "github" ):
994- return json .dumps (
995- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
996- )
990+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
997991
998992 limit = min (limit , MAX_QUERY_ROWS )
999993 conditions , params = [], []
@@ -1024,9 +1018,7 @@ def search_github_commits(
10241018 LIMIT ?""" ,
10251019 [* params , limit ],
10261020 ).fetchall ()
1027- return json .dumps (
1028- {"commits" : _rows_to_dicts (rows ), "count" : len (rows )}, default = str
1029- )
1021+ return json .dumps ({"commits" : _rows_to_dicts (rows ), "count" : len (rows )}, default = str )
10301022
10311023
10321024@mcp .tool (
@@ -1048,9 +1040,7 @@ def search_github_prs(
10481040
10491041 conn = _get_conn ()
10501042 if not _db_attached (conn , "github" ):
1051- return json .dumps (
1052- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
1053- )
1043+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
10541044
10551045 limit = min (limit , MAX_QUERY_ROWS )
10561046 conditions , params = [], []
@@ -1109,9 +1099,7 @@ def search_github_issues(
11091099
11101100 conn = _get_conn ()
11111101 if not _db_attached (conn , "github" ):
1112- return json .dumps (
1113- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
1114- )
1102+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
11151103
11161104 limit = min (limit , MAX_QUERY_ROWS )
11171105 conditions , params = [], []
@@ -1155,9 +1143,7 @@ def github_code_stats(repo: str | None = None) -> str:
11551143 """
11561144 conn = _get_conn ()
11571145 if not _db_attached (conn , "github" ):
1158- return json .dumps (
1159- {"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" }
1160- )
1146+ return json .dumps ({"error" : "github.db not attached. Run: uv run scripts/fetch_github.py --org YOUR_ORG" })
11611147
11621148 result : dict = {}
11631149
0 commit comments