financial-analyst-mcp
README.md
# MCP-Powered Financial Analyst
A local-first AI financial analyst built around a real MCP (Model Context Protocol) server.
Instead of one chatbot guessing at stock trends, two agents work together:
- **Validator agent** — checks data pulled from the internet (Yahoo Finance, news APIs) for
gaps, bad values, or ticker mismatches before anything reaches the LLM.
- **Analyst agent** — reasons over the validated data and MCP tool outputs to write a
structured summary (trend, moving averages, volatility, and relevant news sentiment).
Both agents call tools exposed by a custom **MCP server** — this is the core of the project,
not just LangChain glue code.
## What I added beyond a basic tutorial version
- Two-agent split (Validator → Analyst) instead of one agent doing everything
- A real MCP server with 3 tools, including validation as its own tool
- LangSmith tracing on both agents
- Neon Postgres caching layer (avoids re-hitting rate-limited APIs)
- A small eval suite with hand-calculated ground truth
- A deployed web app (FastAPI on Render, static frontend on Vercel)
## Architecture
```
User query (ticker + date range)
│
▼
Validator agent ──calls──▶ MCP server ──▶ fetch_price_data (Yahoo Finance)
│ ▶ validate_data
│ (retries once on bad data)
▼
Analyst agent ──calls──▶ MCP server ──▶ analyze_chart (moving averages, volatility)
│ ▶ get_news_sentiment
▼
Structured summary + chart data → FastAPI → frontend
```
## Project layout
```
backend/
mcp_server/ # the MCP server + its 3 tools (this is the centerpiece)
agents/ # Validator agent, Analyst agent
orchestration/ # LangGraph wiring: Validator -> Analyst
db/ # Neon Postgres cache + eval result storage
evals/ # hand-checked test cases + eval runner
main.py # FastAPI app, deployed on Render
frontend/
index.html # single-page UI, deployed on Vercel
vercel.json
render.yaml # Render deployment config for the backend
requirements.txt
.env.example
```
## Setup
1. **Clone and install**
```bash
git clone <your-repo-url>
cd financial-analyst-mcp
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
```
2. **Environment variables** — copy `.env.example` to `.env` and fill in:
- `GROQ_API_KEY` — free, no payment required (sign up at console.groq.com), used by the Analyst agent and the news-relevance check
- `DATABASE_URL` — your RDS Postgres connection string
- `NEWSAPI_KEY` — free tier at newsapi.org (100 requests/day, no card required)
- `LANGCHAIN_API_KEY`, `LANGCHAIN_PROJECT` — for LangSmith tracing (optional, free tier)
3. **Set up the database tables**
```bash
python -m backend.db.database --init
```
4. **Run the backend locally**
```bash
uvicorn backend.main:app --reload --port 8000
```
5. **Run the frontend locally** — just open `frontend/index.html` in a browser, or serve it:
```bash
cd frontend && python -m http.server 5500
```
Update the `API_BASE_URL` constant near the top of `index.html` to point at your backend
(`http://localhost:8000` locally, your Render URL once deployed).
6. **Run the eval suite**
```bash
python -m backend.evals.run_evals
```
## Deployment (AWS free tier)
Everything below stays within AWS's 12-month free tier (as long as you pick the free-tier
instance sizes noted). Nothing here needs code changes — the same FastAPI app and MCP server
run as-is.
### 1. Database → RDS (Postgres)
1. AWS Console → RDS → **Create database**.
2. Engine: PostgreSQL. Templates: **Free tier**.
3. Instance class: `db.t3.micro` (or `db.t4g.micro`, whichever the console offers as free tier).
4. Set a master username/password, note them.
5. Under "Connectivity," set **Public access: Yes** (needed so your EC2 instance and your own
machine can reach it — for a portfolio project this is fine; tighten it later if you want).
6. Once it's up, copy the endpoint (looks like `xxxx.rds.amazonaws.com`) and build your
connection string:
```
DATABASE_URL=postgresql://<username>:<password>@<endpoint>:5432/postgres
```
7. In the RDS instance's **Security Group**, add an inbound rule: PostgreSQL (port 5432),
source = your IP (for local testing) and later your EC2 instance's security group.
### 2. Backend → EC2
1. AWS Console → EC2 → **Launch instance**.
2. AMI: Amazon Linux 2023 (or Ubuntu 22.04). Instance type: **t2.micro** (free tier eligible).
3. Create/download a key pair (`.pem` file) — you need this to SSH in.
4. Security group: allow inbound SSH (port 22, your IP) and **custom TCP port 8000** from
anywhere (`0.0.0.0/0`) so the frontend can reach the API.
5. Launch it, then SSH in:
```bash
ssh -i your-key.pem ec2-user@<instance-public-ip>
```
6. On the instance:
```bash
git clone <your-repo-url> financial-analyst-mcp
cd financial-analyst-mcp
nano .env # paste in GROQ_API_KEY (free, from console.groq.com), DATABASE_URL (from RDS), NEWSAPI_KEY, etc.
bash aws/ec2-setup.sh
```
This installs Python, dependencies, creates the database tables, and starts the backend as a
`systemd` service (`financial-analyst`) that keeps running even after you disconnect and
restarts automatically if the instance reboots.
7. Confirm it's up: `curl http://<instance-public-ip>:8000/health`
### 3. Frontend → S3 static website
1. Update `API_BASE_URL` near the top of `frontend/index.html` to
`http://<your-ec2-public-ip>:8000`.
2. From your own machine (with the [AWS CLI](https://aws.amazon.com/cli/) installed and
`aws configure` run once with your credentials):
```bash
BUCKET_NAME=your-unique-bucket-name bash aws/deploy-frontend-s3.sh
```
3. The script creates the bucket, turns on static website hosting, and uploads `index.html`.
It prints your live URL at the end (`http://<bucket>.s3-website-<region>.amazonaws.com`).
4. Whenever you change the frontend, just re-run the same script to re-upload.
### Notes
- EC2's public IP changes if you stop/start the instance (unless you attach an Elastic IP,
which is also free as long as it's attached to a running instance). If your IP changes,
update `API_BASE_URL` and re-run the S3 deploy script.
- To keep costs at zero, stick to the `t2.micro`/`db.t3.micro` free-tier sizes and remember AWS
free tier covers your first 12 months only.
### Will this cost anything on AWS free tier?
**No, as long as you stay within these limits (all part of AWS's 12-month free tier for new accounts):**
| Service | Free tier limit | This project's usage |
|---|---|---|
| EC2 (t2.micro/t3.micro) | 750 hours/month | 1 instance running 24/7 = ~730 hrs — fits inside the limit |
| RDS (db.t3.micro/t4g.micro) | 750 hours/month + 20GB storage | 1 database instance = fits inside the limit |
| S3 | 5GB storage, 20,000 GET / 2,000 PUT requests/month | A single HTML file and light portfolio traffic — nowhere close |
| Data transfer out | 100GB/month (first 12 months) | Portfolio-level traffic won't get near this |
**Things that WILL cost money, so avoid them:**
- Launching a **second** EC2 instance or RDS database at the same time (only your first free-tier
hours per service are free — running two eats double the hours)
- Using a larger instance type than `t2.micro`/`t3.micro` (EC2) or `db.t3.micro`/`db.t4g.micro` (RDS)
- Requesting an **Elastic IP** and then *not* attaching it to a running instance — AWS charges for
unattached Elastic IPs specifically to discourage this
- If your AWS account isn't brand new — free tier is 12 months from account creation, so if you've
had the account longer than that, these services will bill normally
**One safety net worth setting up regardless:** AWS Console → Billing → Budgets → create a budget
alert for $1. It emails you the moment anything starts costing money, so you're never surprised.
## Notes on the MCP layer
The MCP server (`backend/mcp_server/server.py`) is a standalone process that speaks the Model
Context Protocol over stdio. The agents connect to it as MCP clients using
`langchain-mcp-adapters`, which converts the MCP tools into LangChain-compatible tools
automatically. This means the same MCP server could be plugged into Claude Desktop, Cursor, or
any other MCP-compatible host with zero changes — that's the whole point of building it this
way instead of hardcoding tool schemas into the agent.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues