FinMCP-Core
by souzanahamza
README.md
# FinMCP-Backend
Financial AI backend combining **FastAPI**, **Google Gemini**, and **FastMCP**. Exposes Yahoo Finance market data through an MCP stdio server and a Gemini-powered REST chat API for frontend clients.
## Features
- **MCP server (`FinMCP-Core`)** — 15 tools for stock quotes, financials, risk metrics, news sentiment, SEC filings, and session summaries
- **REST API** — `POST /api/chat` endpoint powered by Gemini with automatic function calling
- **Shared service layer** — Yahoo Finance logic centralized in `app/services/market_data.py`
- **Dual run modes** — Web API or stdio MCP server from a single entry point
- **Configurable Gemini model** — set via `GEMINI_MODEL` in `.env`
## Architecture
```
main.py
├── web → FastAPI (app/api.py) → Gemini + fetch_stock_price
└── stdio → FastMCP (app/mcp_server.py) → 15 tools
↓
app/services/market_data.py (yfinance)
```
| Layer | Role |
|-------|------|
| `app/services/market_data.py` | Core yfinance business logic, returns structured `dict` payloads |
| `app/mcp_server.py` | Thin `@mcp.tool()` wrappers for MCP clients (Cursor, Claude Desktop) |
| `app/api.py` | FastAPI app with CORS; Gemini chat with `fetch_stock_price` |
## Prerequisites
- Python 3.10+
- [Google AI API key](https://aistudio.google.com/apikey) (for the web chat API only)
## Installation
```bash
git clone <your-repo-url>
cd finMCP
py -m pip install -r requirements.txt
```
Create a `.env` file in the project root:
```env
GEMINI_API_KEY=your_key_here
GEMINI_MODEL=gemini-2.0-flash
```
| Variable | Required | Description |
|----------|----------|-------------|
| `GEMINI_API_KEY` | Yes (web API) | API key from [Google AI Studio](https://aistudio.google.com/apikey) |
| `GEMINI_MODEL` | No | Gemini model name (default: `gemini-3.1-flash-lite`) |
The MCP stdio server does not require a Gemini API key.
## Running
### Web API (FastAPI)
```bash
py main.py web
```
Server starts at [http://localhost:8000](http://localhost:8000).
- Interactive docs: [http://localhost:8000/docs](http://localhost:8000/docs)
- Health check: `GET /health`
### MCP Server (stdio)
```bash
py main.py
```
Runs the `FinMCP-Core` MCP server over stdio transport for desktop AI clients.
## API Usage
### `POST /api/chat`
Send a natural-language message. Gemini automatically calls `fetch_stock_price` when a stock quote is needed.
**Request:**
```json
{
"message": "What is the current price of AAPL?"
}
```
**Response:**
```json
{
"reply": "Apple Inc. (AAPL): 189.50 USD"
}
```
**Example with curl:**
```bash
curl -X POST http://localhost:8000/api/chat \
-H "Content-Type: application/json" \
-d "{\"message\": \"What is the current price of AAPL?\"}"
```
### Gemini tools (web API)
| Tool | Description |
|------|-------------|
| `fetch_stock_price` | Current price, currency, and company name for a ticker |
### API error responses
| Status | Cause |
|--------|-------|
| `400` | Invalid request or unsupported model configuration |
| `401` | Invalid or unauthorized API key |
| `429` | Gemini rate limit or free-tier quota exceeded |
| `500` | `GEMINI_API_KEY` not configured |
| `502` | Transient or internal Gemini API error |
The chat endpoint retries transient failures automatically via the Google SDK.
## MCP Tools
| Tool | Description |
|------|-------------|
| `get_current_stock_price` | Real-time price and company name |
| `get_historical_stock_splits` | Stock split history |
| `get_stock_info` | Sector, industry, market cap, description |
| `get_financials` | Income, balance sheet, or cash flow statements |
| `get_dividend_analysis` | Dividend yield, payout ratio, history |
| `get_institutional_holders` | Institutional ownership data |
| `get_options_chain` | Calls, puts, and implied volatility |
| `get_news_sentiment` | Filtered news with basic sentiment counts |
| `get_valuation_metrics` | P/E, PEG, EV/EBITDA, price-to-book |
| `get_sector_comparison` | Sector benchmarks and peers |
| `get_risk_metrics` | Beta, volatility, Sharpe ratio, max drawdown |
| `get_earnings_analysis` | EPS estimates vs actuals |
| `get_sec_filings` | SEC filing metadata |
| `add_summary` | Append a message to the session summary file |
| `read_summary` | Read accumulated session summaries |
Session summaries are stored at `app/data/summary.txt` (created automatically on first use).
## Cursor MCP Configuration
Add to your Cursor MCP settings:
```json
{
"mcpServers": {
"finmcp": {
"command": "py",
"args": ["main.py"],
"cwd": "d:\\Desktop\\projects\\finMCP"
}
}
}
```
Adjust `cwd` to match your local project path.
## Project Structure
```
finMCP/
├── app/
│ ├── __init__.py
│ ├── api.py # FastAPI + Gemini chat endpoint
│ ├── mcp_server.py # FastMCP tool registrations
│ ├── data/
│ │ └── summary.txt # Created at runtime
│ └── services/
│ ├── __init__.py
│ └── market_data.py # Yahoo Finance service functions
├── main.py # Entry point (web | stdio)
├── requirements.txt
└── .env # GEMINI_API_KEY, GEMINI_MODEL (not committed)
```
## Troubleshooting
**`GEMINI_API_KEY is not configured`**
Set a valid key in `.env`. The MCP server does not need it.
**`429` / quota exceeded**
Your API key has hit the free-tier or per-minute limit for the configured model. Options:
- Wait and retry (limits reset per minute/day)
- Switch model in `.env`, e.g. `GEMINI_MODEL=gemini-1.5-flash`
- Check usage at [ai.dev/rate-limit](https://ai.dev/rate-limit)
**`500 Internal error` from Gemini**
Often caused by an invalid model name. Use a supported Gemini model (not Gemma or other non-Gemini IDs). Set `GEMINI_MODEL` to a known working value such as `gemini-2.0-flash` or `gemini-1.5-flash`.
**`AttributeError: module 'collections' has no attribute 'Mapping'`**
Upgrade `frozendict` for Python 3.12+ compatibility:
```bash
py -m pip install --upgrade frozendict
```
**`py` or `pip` not found**
Use `python` and `python -m pip` instead, or install Python from [python.org](https://www.python.org/downloads/).
## Dependencies
| Package | Purpose |
|---------|---------|
| `fastapi` / `uvicorn` | Web API server |
| `mcp` | FastMCP stdio server |
| `google-generativeai` | Gemini chat with function calling |
| `yfinance` | Yahoo Finance market data |
| `numpy` | Risk metrics calculations |
| `python-dotenv` | Environment variable loading |
| `pydantic` | Request/response validation |
| `httpx` | HTTP client (transitive dependency) |