Spaces:
Sleeping
Sleeping
| """External data tools: SEC EDGAR, Companies House, currency conversion. | |
| Thin, dependency-light wrappers. Each returns plain dicts so the same | |
| functions back both the MCP server and the in-process LangChain tools. | |
| """ | |
| from __future__ import annotations | |
| import requests | |
| from config import COMPANIES_HOUSE_API_KEY, SEC_EDGAR_USER_AGENT | |
| _TIMEOUT = 20 | |
| def sec_edgar_search(company: str, form_type: str = "10-K", limit: int = 5) -> dict: | |
| """Search recent SEC filings for a company via EDGAR full-text search.""" | |
| try: | |
| resp = requests.get( | |
| "https://efts.sec.gov/LATEST/search-index", | |
| params={"q": company, "forms": form_type}, | |
| headers={"User-Agent": SEC_EDGAR_USER_AGENT}, | |
| timeout=_TIMEOUT, | |
| ) | |
| if resp.status_code != 200: | |
| # fall back to the public full-text search endpoint | |
| resp = requests.get( | |
| "https://efts.sec.gov/LATEST/search-index?q=%22{}%22".format(company), | |
| headers={"User-Agent": SEC_EDGAR_USER_AGENT}, timeout=_TIMEOUT, | |
| ) | |
| resp.raise_for_status() | |
| hits = resp.json().get("hits", {}).get("hits", [])[:limit] | |
| return {"source": "SEC EDGAR", "company": company, "results": [ | |
| {"form": h["_source"].get("form"), "filed": h["_source"].get("file_date"), | |
| "name": h["_source"].get("display_names")} | |
| for h in hits | |
| ]} | |
| except Exception as e: # network optional — never crash the agent loop | |
| return {"source": "SEC EDGAR", "error": str(e)} | |
| def companies_house_search(company: str, limit: int = 5) -> dict: | |
| """Search UK Companies House (requires COMPANIES_HOUSE_API_KEY).""" | |
| if not COMPANIES_HOUSE_API_KEY: | |
| return {"source": "Companies House", "error": "COMPANIES_HOUSE_API_KEY not set"} | |
| try: | |
| resp = requests.get( | |
| "https://api.company-information.service.gov.uk/search/companies", | |
| params={"q": company, "items_per_page": limit}, | |
| auth=(COMPANIES_HOUSE_API_KEY, ""), | |
| timeout=_TIMEOUT, | |
| ) | |
| resp.raise_for_status() | |
| items = resp.json().get("items", []) | |
| return {"source": "Companies House", "company": company, "results": [ | |
| {"title": i.get("title"), "company_number": i.get("company_number"), | |
| "status": i.get("company_status"), "incorporated": i.get("date_of_creation")} | |
| for i in items | |
| ]} | |
| except Exception as e: | |
| return {"source": "Companies House", "error": str(e)} | |
| def convert_currency(amount: float, from_currency: str, to_currency: str) -> dict: | |
| """Convert currency using the free frankfurter.app ECB-rate API.""" | |
| try: | |
| resp = requests.get( | |
| "https://api.frankfurter.app/latest", | |
| params={"amount": amount, "from": from_currency.upper(), "to": to_currency.upper()}, | |
| timeout=_TIMEOUT, | |
| ) | |
| resp.raise_for_status() | |
| data = resp.json() | |
| return {"amount": amount, "from": from_currency.upper(), "to": to_currency.upper(), | |
| "converted": data["rates"].get(to_currency.upper()), "date": data.get("date")} | |
| except Exception as e: | |
| return {"error": str(e)} | |