Skip to main content
Glama
henrysouchien

edgar-mcp

get_filing_sections

Extract specific narrative sections and tables from SEC 10-K or 10-Q filings for financial analysis and research.

Instructions

Parse qualitative sections from SEC 10-K or 10-Q filings and return narrative/tables with metadata.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tickerYes
yearYes
quarterYes
sectionsNo
formatNosummary
max_wordsNo
tables_onlyNo
outputNofile

Implementation Reference

  • _proxy_get_filing_sections: Core handler implementation that proxies requests to remote EDGAR API, processes sections data, handles tables_only filtering, manages file output mode, and writes markdown files when output='file'.
    def _proxy_get_filing_sections(args: dict) -> dict:
        """Proxy filing sections to remote API, with local file-write for output='file'."""
        output_mode = args.get("output", "file")
        sections_list = args.get("sections")
        tables_only = args.get("tables_only", False)
    
        # Build remote API params
        params = {
            "ticker": args["ticker"],
            "year": args["year"],
            "quarter": args["quarter"],
            "format": args.get("format", "summary"),
        }
        if sections_list:
            params["sections"] = ",".join(sections_list)
    
        if output_mode == "file":
            # Fetch full untruncated text for file output
            params["format"] = "full"
            params["max_words"] = "none"
        else:
            max_words = args.get("max_words", 3000)
            params["max_words"] = str(max_words) if max_words is not None else "none"
    
        result = _call_api("/api/sections", params)
    
        if result.get("status") != "success":
            return result
    
        # Normalize section-level table counts for both inline and file modes.
        for section in result.get("sections", {}).values():
            if not isinstance(section, dict):
                continue
            tables = section.get("tables", []) or []
            nonempty_tables = [t for t in tables if (t or "").strip()]
            section["table_count"] = len(nonempty_tables)
        total_tables = sum(
            s.get("table_count", 0)
            for s in result.get("sections", {}).values()
            if isinstance(s, dict)
        )
        if not isinstance(result.get("metadata"), dict):
            result["metadata"] = {}
        result["metadata"]["total_table_count"] = total_tables
    
        # Strip narrative text if tables_only requested
        if tables_only:
            for section in result.get("sections", {}).values():
                if not isinstance(section, dict):
                    continue
                section.pop("text", None)
                table_words = 0
                for table in section.get("tables", []) or []:
                    table_text = (table or "").strip()
                    if table_text:
                        table_words += len(table_text.split())
                section["word_count"] = table_words
    
        if output_mode != "file":
            return result
    
        # Write sections to local markdown file
        ticker = _safe_filename_part(str(args["ticker"]).upper(), "ticker")
        year = int(args["year"])
        quarter = int(args["quarter"])
        filing_type = result.get("filing_type", "")
        sections_data = result.get("sections", {})
    
        FILE_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    
        # Build filename
        if sections_list:
            safe_keys = [_safe_filename_part(key, "section") for key in sorted(sections_list)]
            keys_part = "_".join(safe_keys)
            filename = f"{ticker}_{quarter}Q{year % 100:02d}_{keys_part}.md"
        else:
            filename = f"{ticker}_{quarter}Q{year % 100:02d}_sections.md"
        file_path = (FILE_OUTPUT_DIR / filename).resolve()
        root_dir = FILE_OUTPUT_DIR.resolve()
        if not file_path.is_relative_to(root_dir):
            return {"status": "error", "message": "Invalid output path"}
        if _deadline_expired(args):
            return {"status": "error", "message": "Request timed out before file output could be written"}
    
        # Build markdown
        total_words = sum(s.get("word_count", 0) for s in sections_data.values())
        section_keys = ", ".join(sections_data.keys()) if sections_data else "none"
        lines = [
            f"# {ticker} {filing_type} - Q{quarter} FY{year}: Filing Sections",
            f"> Sections: {section_keys} | Total words: {total_words:,} | Total tables: {total_tables:,}",
            "---",
        ]
        for section in sections_data.values():
            header = section.get("header", "Unknown Section")
            lines.append(f"## SECTION: {header}")
            lines.append(f"**Word count:** {section.get('word_count', 0):,}")
            lines.append(f"**Table count:** {section.get('table_count', 0):,}")
            if not tables_only:
                text = section.get("text", "").strip()
                if text:
                    lines.append(text)
            tables = section.get("tables", [])
            if tables:
                lines.append("### TABLES")
                for table in tables:
                    table_text = (table or "").strip()
                    if table_text:
                        lines.append(table_text)
            lines.append("---")
        if lines and lines[-1] == "---":
            lines.pop()
    
        file_path.write_text("\n".join(lines).strip() + "\n", encoding="utf-8")
    
        # Return summary (no full text inline) + file_path
        summary_sections = {
            key: {
                "header": s.get("header"),
                "word_count": s.get("word_count", 0),
                "table_count": s.get("table_count", 0),
            }
            for key, s in sections_data.items()
        }
        return {
            "status": "success",
            "ticker": ticker,
            "year": year,
            "quarter": quarter,
            "filing_type": filing_type,
            "output": "file",
            "file_path": str(file_path.resolve()),
            "hint": "Use Read tool with file_path. Grep '^## SECTION:' for anchors.",
            "sections": summary_sections,
            "sections_found": list(sections_data.keys()),
            "metadata": {
                "total_word_count": total_words,
                "total_words": total_words,
                "total_table_count": total_tables,
                "section_count": len(sections_data),
            },
        }
  • get_filing_sections: Public MCP tool definition decorated with @mcp.tool() that exposes the filing sections API. Defines input parameters (ticker, year, quarter, sections, format, max_words, tables_only, output) and delegates to _run_tool_guarded.
    @mcp.tool()
    async def get_filing_sections(
        ticker: str,
        year: int,
        quarter: int,
        sections: list[str] | None = None,
        format: Literal["summary", "full"] = "summary",
        max_words: int | None = 3000,
        tables_only: bool = False,
        output: Literal["inline", "file"] = "file",
    ) -> dict:
        """
        Parse qualitative sections from SEC 10-K or 10-Q filings and return
        narrative/tables with metadata.
        """
        args = {
            "ticker": ticker,
            "year": year,
            "quarter": quarter,
            "format": format,
            "max_words": max_words,
            "tables_only": tables_only,
            "output": output,
        }
        if sections:
            args["sections"] = sections
        return await _run_tool_guarded("get_filing_sections", args)
  • Tool registration in _TOOL_DISPATCH and _TOOL_TIMEOUT dictionaries mapping 'get_filing_sections' to its handler function (_proxy_get_filing_sections) and timeout value (60 seconds).
    _TOOL_DISPATCH = {
        "get_filings": _proxy_get_filings,
        "get_financials": _proxy_get_financials,
        "get_metric": _proxy_get_metric,
        "list_metrics": _proxy_list_metrics,
        "search_metrics": _proxy_search_metrics,
        "get_filing_sections": _proxy_get_filing_sections,
    }
    
    _TOOL_TIMEOUT = {
        "get_filings": 30,
        "get_financials": 60,
        "get_metric": 30,
        "list_metrics": 45,
        "search_metrics": 45,
        "get_filing_sections": 60,
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/henrysouchien/edgar-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server