Spaces:
Runtime error
Runtime error
Upload mcp_server_fastmcp.py
Browse files- mcp_server_fastmcp.py +173 -24
mcp_server_fastmcp.py
CHANGED
|
@@ -16,20 +16,38 @@ financial_analyzer = FinancialAnalyzer(
|
|
| 16 |
user_agent="Juntao Peng Financial Report Metrics App (jtyxabc@gmail.com)"
|
| 17 |
)
|
| 18 |
|
| 19 |
-
# Create FastMCP server with pure JSON response
|
| 20 |
-
mcp = FastMCP("sec-financial-data", json_response=True)
|
| 21 |
|
| 22 |
|
| 23 |
@mcp.tool()
|
| 24 |
def search_company(company_name: str) -> dict:
|
| 25 |
"""
|
| 26 |
-
Search for a company by name in SEC EDGAR database.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
Args:
|
| 29 |
-
company_name: Company name to search (e.g., Microsoft, Apple, Tesla)
|
| 30 |
|
| 31 |
Returns:
|
| 32 |
-
dict: Company information
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
"""
|
| 34 |
result = edgar_client.search_company_by_name(company_name)
|
| 35 |
if result:
|
|
@@ -41,13 +59,19 @@ def search_company(company_name: str) -> dict:
|
|
| 41 |
@mcp.tool()
|
| 42 |
def get_company_info(cik: str) -> dict:
|
| 43 |
"""
|
| 44 |
-
Get detailed company information
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
Args:
|
| 47 |
-
cik: Company CIK code
|
| 48 |
|
| 49 |
Returns:
|
| 50 |
-
dict:
|
| 51 |
"""
|
| 52 |
result = edgar_client.get_company_info(cik)
|
| 53 |
if result:
|
|
@@ -59,14 +83,32 @@ def get_company_info(cik: str) -> dict:
|
|
| 59 |
@mcp.tool()
|
| 60 |
def get_company_filings(cik: str, form_types: list[str] | None = None) -> dict:
|
| 61 |
"""
|
| 62 |
-
Get list of
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
Args:
|
| 65 |
cik: Company CIK code
|
| 66 |
-
form_types: Optional filter by form types (e.g., [10-K, 10-Q])
|
|
|
|
| 67 |
|
| 68 |
Returns:
|
| 69 |
-
dict:
|
|
|
|
|
|
|
|
|
|
| 70 |
"""
|
| 71 |
result = edgar_client.get_company_filings(cik, form_types)
|
| 72 |
if result:
|
|
@@ -83,14 +125,33 @@ def get_company_filings(cik: str, form_types: list[str] | None = None) -> dict:
|
|
| 83 |
@mcp.tool()
|
| 84 |
def get_financial_data(cik: str, period: str) -> dict:
|
| 85 |
"""
|
| 86 |
-
Get financial data for a specific period
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
Args:
|
| 89 |
cik: Company CIK code
|
| 90 |
-
period:
|
|
|
|
| 91 |
|
| 92 |
Returns:
|
| 93 |
-
dict: Financial
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
"""
|
| 95 |
result = edgar_client.get_financial_data_for_period(cik, period)
|
| 96 |
if result and "period" in result:
|
|
@@ -102,15 +163,52 @@ def get_financial_data(cik: str, period: str) -> dict:
|
|
| 102 |
@mcp.tool()
|
| 103 |
def extract_financial_metrics(cik: str, years: int = 3) -> dict:
|
| 104 |
"""
|
| 105 |
-
Extract comprehensive financial metrics
|
| 106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
Args:
|
| 109 |
cik: Company CIK code
|
| 110 |
years: Number of recent years to extract (1-10, default: 3)
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
Returns:
|
| 113 |
-
dict:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
"""
|
| 115 |
if years < 1 or years > 10:
|
| 116 |
return {"error": "Years parameter must be between 1 and 10"}
|
|
@@ -165,13 +263,40 @@ def extract_financial_metrics(cik: str, years: int = 3) -> dict:
|
|
| 165 |
@mcp.tool()
|
| 166 |
def get_latest_financial_data(cik: str) -> dict:
|
| 167 |
"""
|
| 168 |
-
Get the most recent financial
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
Args:
|
| 171 |
cik: Company CIK code
|
| 172 |
|
| 173 |
Returns:
|
| 174 |
-
dict: Latest financial data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
"""
|
| 176 |
result = financial_analyzer.get_latest_financial_data(cik)
|
| 177 |
if result and "period" in result:
|
|
@@ -183,13 +308,37 @@ def get_latest_financial_data(cik: str) -> dict:
|
|
| 183 |
@mcp.tool()
|
| 184 |
def advanced_search_company(company_input: str) -> dict:
|
| 185 |
"""
|
| 186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
| 188 |
Args:
|
| 189 |
-
company_input:
|
| 190 |
|
| 191 |
Returns:
|
| 192 |
-
dict:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
"""
|
| 194 |
result = financial_analyzer.search_company(company_input)
|
| 195 |
if result.get("error"):
|
|
@@ -216,5 +365,5 @@ if __name__ == "__main__":
|
|
| 216 |
|
| 217 |
uvicorn.Config.__init__ = patched_init
|
| 218 |
|
| 219 |
-
# Run FastMCP with
|
| 220 |
-
mcp.run(transport="
|
|
|
|
| 16 |
user_agent="Juntao Peng Financial Report Metrics App (jtyxabc@gmail.com)"
|
| 17 |
)
|
| 18 |
|
| 19 |
+
# Create FastMCP server with pure JSON response and stateless HTTP
|
| 20 |
+
mcp = FastMCP("sec-financial-data", json_response=True, stateless_http=True)
|
| 21 |
|
| 22 |
|
| 23 |
@mcp.tool()
|
| 24 |
def search_company(company_name: str) -> dict:
|
| 25 |
"""
|
| 26 |
+
Search for a company by name in the SEC EDGAR database. Use this tool when the user mentions
|
| 27 |
+
a company name or asks about a company without providing its CIK code. This tool will find the
|
| 28 |
+
company's official information needed for other financial queries.
|
| 29 |
+
|
| 30 |
+
When to use:
|
| 31 |
+
- User mentions a company name (e.g., "Tesla", "Apple", "Microsoft")
|
| 32 |
+
- Need to find a company's CIK code for other tool calls
|
| 33 |
+
- User asks "tell me about [company name]"
|
| 34 |
+
- Need to verify company ticker symbols
|
| 35 |
+
|
| 36 |
+
Examples:
|
| 37 |
+
- "Search for Tesla" β Returns Tesla's CIK, ticker (TSLA), and industry info
|
| 38 |
+
- "Find Apple" β Returns Apple's CIK, ticker (AAPL), and classification
|
| 39 |
+
- "What's Microsoft's CIK?" β Returns CIK code and full company details
|
| 40 |
|
| 41 |
Args:
|
| 42 |
+
company_name: Company name to search (e.g., "Microsoft", "Apple Inc", "Tesla Motors")
|
| 43 |
|
| 44 |
Returns:
|
| 45 |
+
dict: Company information containing:
|
| 46 |
+
- cik: Company Central Index Key (unique identifier needed for other tools)
|
| 47 |
+
- name: Official company name registered with SEC
|
| 48 |
+
- tickers: Stock ticker symbol(s) (e.g., ["TSLA"], ["AAPL"])
|
| 49 |
+
- sic: Standard Industrial Classification code
|
| 50 |
+
- sic_description: Industry/sector description
|
| 51 |
"""
|
| 52 |
result = edgar_client.search_company_by_name(company_name)
|
| 53 |
if result:
|
|
|
|
| 59 |
@mcp.tool()
|
| 60 |
def get_company_info(cik: str) -> dict:
|
| 61 |
"""
|
| 62 |
+
Get detailed company information using CIK code. Use this when you already have a company's
|
| 63 |
+
CIK code and need to retrieve or verify its official details.
|
| 64 |
+
|
| 65 |
+
When to use:
|
| 66 |
+
- Already have a CIK code from search_company
|
| 67 |
+
- Need to verify company details
|
| 68 |
+
- User provides a CIK code directly
|
| 69 |
|
| 70 |
Args:
|
| 71 |
+
cik: Company CIK code in 10-digit format (e.g., "0000789019" for Microsoft)
|
| 72 |
|
| 73 |
Returns:
|
| 74 |
+
dict: Detailed company information including name, tickers, SIC code, and industry description
|
| 75 |
"""
|
| 76 |
result = edgar_client.get_company_info(cik)
|
| 77 |
if result:
|
|
|
|
| 83 |
@mcp.tool()
|
| 84 |
def get_company_filings(cik: str, form_types: list[str] | None = None) -> dict:
|
| 85 |
"""
|
| 86 |
+
Get a list of SEC filings for a company. SEC filings are official documents companies must
|
| 87 |
+
submit, including annual reports (10-K), quarterly reports (10-Q), and foreign company
|
| 88 |
+
annual reports (20-F). Use this to see what reports are available or to get filing dates.
|
| 89 |
+
|
| 90 |
+
When to use:
|
| 91 |
+
- User asks "what reports has [company] filed?"
|
| 92 |
+
- Need to see filing history or dates
|
| 93 |
+
- Want to know what documents are available
|
| 94 |
+
- Checking if specific report types exist
|
| 95 |
+
|
| 96 |
+
Common form types:
|
| 97 |
+
- 10-K: Annual report (comprehensive yearly financial statement)
|
| 98 |
+
- 10-Q: Quarterly report (financial updates every 3 months)
|
| 99 |
+
- 20-F: Annual report for foreign companies
|
| 100 |
+
- 8-K: Current report (major events/changes)
|
| 101 |
|
| 102 |
Args:
|
| 103 |
cik: Company CIK code
|
| 104 |
+
form_types: Optional list to filter by specific form types (e.g., ["10-K", "10-Q"])
|
| 105 |
+
If None, returns all filing types
|
| 106 |
|
| 107 |
Returns:
|
| 108 |
+
dict: Filing information containing:
|
| 109 |
+
- total: Total number of filings found
|
| 110 |
+
- returned: Number of filings in response (max 20)
|
| 111 |
+
- filings: List of filing details with dates, form types, and document links
|
| 112 |
"""
|
| 113 |
result = edgar_client.get_company_filings(cik, form_types)
|
| 114 |
if result:
|
|
|
|
| 125 |
@mcp.tool()
|
| 126 |
def get_financial_data(cik: str, period: str) -> dict:
|
| 127 |
"""
|
| 128 |
+
Get financial data for a specific time period (year or quarter). Use this when the user asks
|
| 129 |
+
about financials for a particular period, like "2024 results" or "Q3 2024 performance".
|
| 130 |
+
|
| 131 |
+
When to use:
|
| 132 |
+
- User specifies a particular year (e.g., "2024 financials")
|
| 133 |
+
- User asks about a specific quarter (e.g., "Q3 2024 results")
|
| 134 |
+
- Need data for a single, specific time period
|
| 135 |
+
- Comparing specific periods (call multiple times)
|
| 136 |
+
|
| 137 |
+
Period format:
|
| 138 |
+
- Annual: "YYYY" (e.g., "2024" for fiscal year 2024)
|
| 139 |
+
- Quarterly: "YYYYQX" (e.g., "2024Q3" for Q3 of 2024, "2023Q4" for Q4 of 2023)
|
| 140 |
|
| 141 |
Args:
|
| 142 |
cik: Company CIK code
|
| 143 |
+
period: Time period in format "YYYY" for annual or "YYYYQX" for quarterly
|
| 144 |
+
Examples: "2024", "2023", "2024Q3", "2023Q4"
|
| 145 |
|
| 146 |
Returns:
|
| 147 |
+
dict: Financial metrics for the specified period including:
|
| 148 |
+
- total_revenue: Total sales/revenue for the period
|
| 149 |
+
- net_income: Profit (or loss) after all expenses
|
| 150 |
+
- earnings_per_share: Profit per share of stock (EPS)
|
| 151 |
+
- operating_expenses: Costs of running business operations
|
| 152 |
+
- operating_cash_flow: Cash generated from business operations
|
| 153 |
+
- source_url: Link to the SEC filing document
|
| 154 |
+
- source_form: Type of SEC form (10-K, 10-Q, or 20-F)
|
| 155 |
"""
|
| 156 |
result = edgar_client.get_financial_data_for_period(cik, period)
|
| 157 |
if result and "period" in result:
|
|
|
|
| 163 |
@mcp.tool()
|
| 164 |
def extract_financial_metrics(cik: str, years: int = 3) -> dict:
|
| 165 |
"""
|
| 166 |
+
Extract comprehensive financial metrics spanning multiple years with both annual and quarterly
|
| 167 |
+
data. This is the MOST POWERFUL tool for financial analysis - it returns complete multi-year
|
| 168 |
+
trends including all quarters. Perfect for understanding company performance over time,
|
| 169 |
+
identifying growth patterns, and comprehensive financial analysis.
|
| 170 |
+
|
| 171 |
+
When to use (RECOMMENDED for most financial analysis):
|
| 172 |
+
- User asks about "trends over time"
|
| 173 |
+
- Questions about "growth", "performance over years"
|
| 174 |
+
- "Show me [company]'s financials" (without specifying a period)
|
| 175 |
+
- Comparative analysis needs
|
| 176 |
+
- "How has [company] been doing?"
|
| 177 |
+
- ANY request for multiple periods of data
|
| 178 |
+
|
| 179 |
+
What makes this tool special:
|
| 180 |
+
- Returns BOTH annual (FY) and quarterly (Q1-Q4) data
|
| 181 |
+
- Sorted newest to oldest (FY2024 β Q4 β Q3 β Q2 β Q1 β FY2023...)
|
| 182 |
+
- Includes multiple years in one call (saves time)
|
| 183 |
+
- Ideal for trend analysis and year-over-year comparisons
|
| 184 |
+
|
| 185 |
+
Example use cases:
|
| 186 |
+
- "Show Tesla's financial trends for 3 years" β Perfect use case
|
| 187 |
+
- "How has Apple's revenue grown?" β Use this (default 3 years)
|
| 188 |
+
- "Compare Microsoft's quarterly performance" β Returns all quarters
|
| 189 |
+
- "What are Amazon's financial metrics?" β Comprehensive overview
|
| 190 |
|
| 191 |
Args:
|
| 192 |
cik: Company CIK code
|
| 193 |
years: Number of recent years to extract (1-10, default: 3)
|
| 194 |
+
- 3 years = ~15 data points (3 annual + ~12 quarterly)
|
| 195 |
+
- 5 years = ~25 data points (5 annual + ~20 quarterly)
|
| 196 |
+
- More years = more comprehensive trend analysis
|
| 197 |
|
| 198 |
Returns:
|
| 199 |
+
dict: Comprehensive financial dataset containing:
|
| 200 |
+
- periods: Total number of time periods returned
|
| 201 |
+
- data: List of financial records, each with:
|
| 202 |
+
* period: Time identifier (e.g., "FY2024", "2024Q3", "2023Q1")
|
| 203 |
+
* total_revenue: Company's total sales/revenue for that period
|
| 204 |
+
* net_income: Profit after all expenses (can be negative for losses)
|
| 205 |
+
* earnings_per_share: Profit per share of stock (EPS)
|
| 206 |
+
* operating_expenses: Costs of running the business
|
| 207 |
+
* operating_cash_flow: Actual cash generated from operations
|
| 208 |
+
* source_url: Link to SEC filing document
|
| 209 |
+
* source_form: SEC form type (10-K for annual, 10-Q for quarterly)
|
| 210 |
+
|
| 211 |
+
Data is sorted newest first: FY2024 β 2024Q4 β 2024Q3 β 2024Q2 β 2024Q1 β FY2023...
|
| 212 |
"""
|
| 213 |
if years < 1 or years > 10:
|
| 214 |
return {"error": "Years parameter must be between 1 and 10"}
|
|
|
|
| 263 |
@mcp.tool()
|
| 264 |
def get_latest_financial_data(cik: str) -> dict:
|
| 265 |
"""
|
| 266 |
+
Get the most recent financial snapshot for a company - returns only the latest annual report
|
| 267 |
+
data. Use this for quick checks of current financial status or when the user asks about
|
| 268 |
+
"latest" or "most recent" results without needing historical data.
|
| 269 |
+
|
| 270 |
+
When to use:
|
| 271 |
+
- User asks "what are [company]'s latest financials?"
|
| 272 |
+
- "How is [company] doing currently?"
|
| 273 |
+
- "Show me [company]'s most recent results"
|
| 274 |
+
- Quick status check without historical context
|
| 275 |
+
- Need just the newest data point (faster than extract_financial_metrics)
|
| 276 |
+
|
| 277 |
+
What this returns:
|
| 278 |
+
- Only the most recent ANNUAL (fiscal year) data
|
| 279 |
+
- Does NOT include quarterly breakdowns
|
| 280 |
+
- Fastest way to get current snapshot
|
| 281 |
+
|
| 282 |
+
Examples:
|
| 283 |
+
- "What's Tesla's latest revenue?" β Returns most recent annual revenue
|
| 284 |
+
- "How much did Apple earn recently?" β Returns latest annual net income
|
| 285 |
+
- "Show me Microsoft's current financials" β Returns latest fiscal year data
|
| 286 |
|
| 287 |
Args:
|
| 288 |
cik: Company CIK code
|
| 289 |
|
| 290 |
Returns:
|
| 291 |
+
dict: Latest financial data from most recent fiscal year including:
|
| 292 |
+
- period: The fiscal year (e.g., "FY2024")
|
| 293 |
+
- total_revenue: Most recent annual revenue
|
| 294 |
+
- net_income: Most recent annual profit
|
| 295 |
+
- earnings_per_share: Latest annual EPS
|
| 296 |
+
- operating_expenses: Latest annual operating costs
|
| 297 |
+
- operating_cash_flow: Latest annual cash from operations
|
| 298 |
+
- source_url: Link to the SEC filing
|
| 299 |
+
- source_form: SEC form type (usually 10-K or 20-F)
|
| 300 |
"""
|
| 301 |
result = financial_analyzer.get_latest_financial_data(cik)
|
| 302 |
if result and "period" in result:
|
|
|
|
| 308 |
@mcp.tool()
|
| 309 |
def advanced_search_company(company_input: str) -> dict:
|
| 310 |
"""
|
| 311 |
+
Flexible smart search that accepts ANY type of company identifier - company name, stock ticker
|
| 312 |
+
symbol (like TSLA, AAPL, MSFT), or CIK code. The tool automatically detects what type of
|
| 313 |
+
identifier you provide. Use this when you're uncertain what type of identifier the user gave.
|
| 314 |
+
|
| 315 |
+
When to use:
|
| 316 |
+
- User provides just a ticker symbol (e.g., "TSLA", "AAPL")
|
| 317 |
+
- Unclear if user gave name, ticker, or CIK
|
| 318 |
+
- Want most flexible search option
|
| 319 |
+
- User input could be any identifier type
|
| 320 |
+
|
| 321 |
+
What it accepts:
|
| 322 |
+
- Company names: "Tesla", "Apple Inc", "Microsoft Corporation"
|
| 323 |
+
- Ticker symbols: "TSLA", "AAPL", "MSFT", "GOOGL"
|
| 324 |
+
- CIK codes: "0001318605", "0000320193"
|
| 325 |
+
|
| 326 |
+
Examples:
|
| 327 |
+
- Input: "TSLA" β Recognizes as ticker, returns Tesla info
|
| 328 |
+
- Input: "Tesla" β Searches by name, returns Tesla info
|
| 329 |
+
- Input: "0001318605" β Recognizes as CIK, returns Tesla info
|
| 330 |
+
- Input: "AAPL" β Returns Apple information
|
| 331 |
|
| 332 |
Args:
|
| 333 |
+
company_input: Any company identifier - name ("Tesla"), ticker ("TSLA"), or CIK ("0001318605")
|
| 334 |
|
| 335 |
Returns:
|
| 336 |
+
dict: Complete company information including:
|
| 337 |
+
- cik: Company's Central Index Key
|
| 338 |
+
- name: Official registered company name
|
| 339 |
+
- tickers: Stock ticker symbol(s)
|
| 340 |
+
- sic: Standard Industrial Classification code
|
| 341 |
+
- sic_description: Industry/sector description
|
| 342 |
"""
|
| 343 |
result = financial_analyzer.search_company(company_input)
|
| 344 |
if result.get("error"):
|
|
|
|
| 365 |
|
| 366 |
uvicorn.Config.__init__ = patched_init
|
| 367 |
|
| 368 |
+
# Run FastMCP with HTTP transport (stateless mode)
|
| 369 |
+
mcp.run(transport="http")
|