"""MCP server exposing the tool layer over the Model Context Protocol. Run standalone: python -m src.tools.mcp_server Any MCP-capable client (Claude Desktop, LangChain MCP adapters, etc.) can then call the ratio engine, filings search, and currency conversion. The same underlying functions are also exposed in-process as LangChain tools (src/tools/langchain_tools.py) so the Gradio app works without a separate server process. """ from __future__ import annotations from mcp.server.fastmcp import FastMCP from src.tools import external, ratios mcp = FastMCP("financial-analyst-tools") @mcp.tool() def calculate_ratio(name: str, inputs: dict[str, float]) -> dict: """Compute a financial ratio. `name` is one of: roe, roa, ebitda_margin, current_ratio, quick_ratio, debt_to_equity, interest_coverage, free_cash_flow. `inputs` maps the formula's argument names to figures. """ return ratios.compute(name, **inputs).as_dict() @mcp.tool() def calculator(expression: str) -> float: """Evaluate a plain arithmetic expression, e.g. '(1200 - 950) / 950'.""" allowed = set("0123456789.+-*/() eE") if not set(expression) <= allowed: raise ValueError("Only arithmetic characters are allowed") return float(eval(expression, {"__builtins__": {}}, {})) # noqa: S307 — charset-restricted @mcp.tool() def sec_edgar_search(company: str, form_type: str = "10-K") -> dict: """Search recent SEC EDGAR filings for a company.""" return external.sec_edgar_search(company, form_type) @mcp.tool() def companies_house_search(company: str) -> dict: """Search UK Companies House for a company's registration details.""" return external.companies_house_search(company) @mcp.tool() def convert_currency(amount: float, from_currency: str, to_currency: str) -> dict: """Convert an amount between currencies at current ECB rates.""" return external.convert_currency(amount, from_currency, to_currency) @mcp.tool() def convert_file_to_markdown(path: str) -> str: """Convert a financial document (PDF, CSV, XLSX/XLS, JSON, PNG/JPG via OCR, or plain text) into clean Markdown with intact tables — the normalised form used for embedding and analysis.""" from src.ingestion.loader import to_markdown return to_markdown(path) if __name__ == "__main__": mcp.run()