Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions packages/arxiv-mcp/src/arxiv_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,19 @@ def parse_arxiv_entry(entry: ET.Element) -> dict[str, Any]:
"""
# Extract basic metadata
title = entry.find("atom:title", ARXIV_NAMESPACE)
title_text = title.text.strip().replace("\n", " ") if title is not None else "Unknown"
title_text = (
title.text.strip().replace("\n", " ")
if title is not None and title.text is not None
else "Unknown"
)

# Extract ArXiv ID from the entry ID
entry_id = entry.find("atom:id", ARXIV_NAMESPACE)
arxiv_id = entry_id.text.split("/abs/")[-1] if entry_id is not None else "Unknown"
arxiv_id = (
entry_id.text.split("/abs/")[-1]
if entry_id is not None and entry_id.text is not None
else "Unknown"
)

# Extract authors
authors = []
Expand All @@ -91,7 +99,11 @@ def parse_arxiv_entry(entry: ET.Element) -> dict[str, Any]:

# Extract summary (abstract)
summary = entry.find("atom:summary", ARXIV_NAMESPACE)
summary_text = summary.text.strip().replace("\n", " ") if summary is not None else ""
summary_text = (
summary.text.strip().replace("\n", " ")
if summary is not None and summary.text is not None
else ""
)

# Extract published date
published = entry.find("atom:published", ARXIV_NAMESPACE)
Expand Down Expand Up @@ -186,7 +198,8 @@ async def call_openai_api(prompt: str, model: str = "gpt-4") -> str | None:
response = await client.post(url, headers=headers, json=payload, timeout=60.0)
response.raise_for_status()
result = response.json()
return result["choices"][0]["message"]["content"]
content: str | None = result["choices"][0]["message"]["content"]
return content
except httpx.HTTPError as e:
logger.error(f"OpenAI API error: {e}")
return None
Expand Down Expand Up @@ -229,7 +242,8 @@ async def call_anthropic_api(prompt: str, model: str = "claude-3-5-sonnet-202410
response = await client.post(url, headers=headers, json=payload, timeout=60.0)
response.raise_for_status()
result = response.json()
return result["content"][0]["text"]
text: str | None = result["content"][0]["text"]
return text
except httpx.HTTPError as e:
logger.error(f"Anthropic API error: {e}")
return None
Expand Down Expand Up @@ -390,7 +404,7 @@ async def summarize_paper_with_llm(
A concise summary of the paper generated by the LLM
"""
# First, fetch the paper details
paper_info = await get_arxiv_paper(arxiv_id)
paper_info: str = await get_arxiv_paper(arxiv_id)

if paper_info.startswith("Error:") or paper_info.startswith("Paper not found:"):
return paper_info
Expand Down Expand Up @@ -460,7 +474,7 @@ async def search_and_summarize(
max_papers = min(max_papers, 5)

# First, search for papers
search_results = await search_arxiv(query, max_results=max_papers)
search_results: str = await search_arxiv(query, max_results=max_papers)

if search_results.startswith("Error:") or search_results.startswith("No papers found"):
return search_results
Expand All @@ -481,7 +495,7 @@ async def search_and_summarize(

for i, arxiv_id in enumerate(arxiv_ids, 1):
logger.info(f"Summarizing paper {i}/{len(arxiv_ids)}: {arxiv_id}")
summary = await summarize_paper_with_llm(arxiv_id, llm_provider)
summary: str = await summarize_paper_with_llm(arxiv_id, llm_provider)
summaries.append(f"\n{i}. {summary}")
summaries.append("=" * 80)

Expand Down
26 changes: 13 additions & 13 deletions packages/bgs-mcp/src/bgs_mcp/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ async def list_commodities(
else:
commodities = await client.get_commodities()

categories = None
categories: dict[str, list[str]] | None = None
if categorize:
categories = {
"battery": [],
Expand Down Expand Up @@ -443,17 +443,17 @@ async def get_time_series(

# Aggregate by year if no country specified
if not country:
year_totals = {}
year_totals: dict[int, float] = {}
units = None
for r in records:
if r.year and r.quantity is not None:
if r.year not in year_totals:
year_totals[r.year] = 0
year_totals[r.year] = 0.0
year_totals[r.year] += r.quantity
units = r.units

data = []
prev_qty = None
prev_qty: float | None = None
for year in sorted(year_totals.keys()):
qty = year_totals[year]
yoy = None
Expand All @@ -474,16 +474,16 @@ async def get_time_series(
units = records[0].units if records else None

data = []
prev_qty = None
prev_qty_r: float | None = None
for r in records:
if r.year and r.quantity is not None:
yoy = None
if prev_qty and prev_qty > 0:
yoy = round(((r.quantity - prev_qty) / prev_qty) * 100, 2)
if prev_qty_r and prev_qty_r > 0:
yoy = round(((r.quantity - prev_qty_r) / prev_qty_r) * 100, 2)
data.append(
TimeSeriesPoint(year=r.year, quantity=r.quantity, yoy_change_percent=yoy)
)
prev_qty = r.quantity
prev_qty_r = r.quantity

return TimeSeriesResponse(
commodity=commodity,
Expand Down Expand Up @@ -554,7 +554,7 @@ async def get_country_profile(
client = get_client()

country_iso = None
country_name = country
country_name: str | None = country
if len(country) <= 3:
country_iso = country
country_name = None
Expand All @@ -576,7 +576,7 @@ async def get_country_profile(
year = max(available_years)

# Aggregate by commodity
commodity_data = {}
commodity_data: dict[str, dict[str, Any]] = {}
for r in records:
if r.year != year:
continue
Expand All @@ -585,19 +585,19 @@ async def get_country_profile(

key = r.commodity
if key not in commodity_data:
commodity_data[key] = {"commodity": key, "quantity": 0, "units": r.units}
commodity_data[key] = {"commodity": key, "quantity": 0.0, "units": r.units}
commodity_data[key]["quantity"] += r.quantity

# Sort by quantity
commodities = sorted(
commodity_data.values(),
key=lambda x: x["quantity"],
key=lambda x: float(x["quantity"]),
reverse=True,
)

return CountryProfile(
country=actual_country,
year=year,
year=year if year is not None else 0,
statistic_type=statistic_type,
commodities=commodities,
)
Expand Down
12 changes: 6 additions & 6 deletions packages/bgs-mcp/src/bgs_mcp/bgs_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from typing import Any
from typing import Any, cast

import httpx
from pydantic import BaseModel
Expand Down Expand Up @@ -104,7 +104,7 @@ async def _request(
headers={"Accept": "application/json"},
)
response.raise_for_status()
return response.json()
return cast(dict[str, Any], response.json())

def _parse_records(self, data: dict[str, Any]) -> list[MineralRecord]:
"""Parse API response into MineralRecord objects."""
Expand Down Expand Up @@ -206,7 +206,7 @@ async def search_production(
params["country_iso3_code"] = country_iso.upper()

# Fetch data
all_records = []
all_records: list[MineralRecord] = []
offset = 0

while len(all_records) < limit:
Expand Down Expand Up @@ -303,7 +303,7 @@ async def get_commodity_by_country(
year = max(r.year for r in records if r.year)

# Filter to target year and aggregate by country
country_totals = {}
country_totals: dict[str, dict[str, Any]] = {}

for record in records:
if record.year != year:
Expand All @@ -316,7 +316,7 @@ async def get_commodity_by_country(
country_totals[country] = {
"country": country,
"country_iso3": record.country_iso3,
"quantity": 0,
"quantity": 0.0,
"units": record.units,
"year": year,
}
Expand All @@ -325,7 +325,7 @@ async def get_commodity_by_country(
# Sort by quantity descending
ranked = sorted(
country_totals.values(),
key=lambda x: x["quantity"],
key=lambda x: float(x["quantity"]),
reverse=True,
)

Expand Down
22 changes: 11 additions & 11 deletions packages/bgs-mcp/src/bgs_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,12 @@ async def get_time_series(

# If no country specified, aggregate by year
if not country:
year_totals = {}
year_totals: dict[int, float] = {}
units = None
for r in records:
if r.year and r.quantity is not None:
if r.year not in year_totals:
year_totals[r.year] = 0
year_totals[r.year] = 0.0
year_totals[r.year] += r.quantity
units = r.units

Expand Down Expand Up @@ -323,16 +323,16 @@ async def get_time_series(
output += "| Year | Quantity | YoY Change |\n"
output += "|------|----------|------------|\n"

prev_qty = None
prev_qty_r: float | None = None
for r in records:
if r.year and r.quantity is not None:
if prev_qty and prev_qty > 0:
change = ((r.quantity - prev_qty) / prev_qty) * 100
if prev_qty_r and prev_qty_r > 0:
change = ((r.quantity - prev_qty_r) / prev_qty_r) * 100
change_str = f"{change:+.1f}%"
else:
change_str = "-"
output += f"| {r.year} | {r.quantity:,.1f} | {change_str} |\n"
prev_qty = r.quantity
prev_qty_r = r.quantity

return output

Expand Down Expand Up @@ -431,7 +431,7 @@ async def get_country_profile(
client = get_client()

country_iso = None
country_name = country
country_name: str | None = country
if len(country) <= 3:
country_iso = country
country_name = None
Expand All @@ -454,7 +454,7 @@ async def get_country_profile(
year = max(available_years)

# Filter to target year and aggregate by commodity
commodity_data = {}
commodity_data: dict[str, dict[str, float | str | None]] = {}
for r in records:
if r.year != year:
continue
Expand All @@ -463,8 +463,8 @@ async def get_country_profile(

key = r.commodity
if key not in commodity_data:
commodity_data[key] = {"quantity": 0, "units": r.units}
commodity_data[key]["quantity"] += r.quantity
commodity_data[key] = {"quantity": 0.0, "units": r.units}
commodity_data[key]["quantity"] = float(commodity_data[key]["quantity"] or 0) + r.quantity

output = f"**{actual_country} - {statistic_type} Profile ({year})**\n\n"
output += f"Commodities: {len(commodity_data)}\n\n"
Expand All @@ -475,7 +475,7 @@ async def get_country_profile(
# Sort by quantity descending
sorted_commodities = sorted(
commodity_data.items(),
key=lambda x: x[1]["quantity"],
key=lambda x: float(x[1]["quantity"] or 0),
reverse=True,
)

Expand Down
2 changes: 1 addition & 1 deletion packages/claimm-mcp/src/claimm_mcp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,5 @@ def get_settings() -> Settings:
"""Get or create the settings instance."""
global _settings
if _settings is None:
_settings = Settings()
_settings = Settings() # type: ignore[call-arg]
return _settings
3 changes: 2 additions & 1 deletion packages/claimm-mcp/src/claimm_mcp/edx_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ async def _request(
error = result.get("error", {})
raise Exception(f"EDX API error: {error}")

return result.get("result", {})
api_result: dict[str, Any] = result.get("result", {})
return api_result

async def search_resources(
self,
Expand Down
2 changes: 1 addition & 1 deletion packages/claimm-mcp/src/claimm_mcp/header_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def _detect_delimiter(self, line: str) -> str:
"""Auto-detect CSV delimiter."""
delimiters = [",", "\t", ";", "|"]
counts = {d: line.count(d) for d in delimiters}
return max(counts, key=counts.get) if max(counts.values()) > 0 else ","
return max(counts, key=lambda d: counts[d]) if max(counts.values()) > 0 else ","

def _detect_column_types(
self,
Expand Down
8 changes: 4 additions & 4 deletions packages/claimm-mcp/src/claimm_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ async def detect_dataset_schemas(
output += "\n"

# Show column types summary
types = {}
types: dict[str, int] = {}
for col in result.get("column_types", []):
t = col.get("type", "unknown")
types[t] = types.get(t, 0) + 1
Expand Down Expand Up @@ -428,9 +428,9 @@ async def ask_about_data(
if dataset_id:
submission = await edx.get_submission(dataset_id)
# Use the first resource as context if available
resource = submission.resources[0] if submission.resources else None
if resource:
return await llm.answer_about_resource(resource, submission, question)
first_resource = submission.resources[0] if submission.resources else None
if first_resource:
return await llm.answer_about_resource(first_resource, submission, question)
else:
# Answer based on submission only
try:
Expand Down
2 changes: 1 addition & 1 deletion packages/cmm-data/src/cmm_data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def load_ore_deposits(table: str = "all"):
from .loaders.usgs_ore import USGSOreDepositsLoader

loader = USGSOreDepositsLoader()
return loader.load(table)
return loader.load(table=table)


def search_documents(query: str, **kwargs):
Expand Down
10 changes: 5 additions & 5 deletions packages/cmm-data/src/cmm_data/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def search_all_datasets(query: str, datasets: list[str] | None = None) -> pd.Dat

if "usgs_commodity" in datasets:
try:
loader = USGSCommodityLoader()
USGSCommodityLoader() # Validate loader availability
# Search commodity names
for code, name in COMMODITY_NAMES.items():
if query.lower() in name.lower() or query.lower() in code.lower():
Expand All @@ -175,8 +175,8 @@ def search_all_datasets(query: str, datasets: list[str] | None = None) -> pd.Dat

if "osti" in datasets:
try:
loader = OSTIDocumentsLoader()
docs = loader.search_documents(query, limit=20)
osti_loader = OSTIDocumentsLoader()
docs = osti_loader.search_documents(query, limit=20)
for _, row in docs.iterrows():
results.append(
{
Expand All @@ -192,8 +192,8 @@ def search_all_datasets(query: str, datasets: list[str] | None = None) -> pd.Dat

if "preprocessed" in datasets:
try:
loader = PreprocessedCorpusLoader()
docs = loader.search(query, limit=20)
preprocessed_loader = PreprocessedCorpusLoader()
docs = preprocessed_loader.search(query, limit=20)
for _, row in docs.iterrows():
results.append(
{
Expand Down
Loading
Loading