This project demonstrates two different approaches to fetching stock data from Alpha Vantage:
- REST Example: Traditional direct API integration
- MCP Example: Model Context Protocol with plugin architecture
This is a learning project designed to showcase the architectural differences between:
- Direct REST API calls (tightly coupled, stateless)
- MCP protocol integration (abstracted, pluggable, stateful)
Both implementations fetch the same stock quote data, making it easy to compare the approaches.
Visual comparison: Side-by-side architecture diagrams showing REST (blue) vs MCP (green) approaches.
| Aspect | REST Approach | MCP Approach |
|---|---|---|
| Communication | Direct HTTP GET requests | JSON-RPC over http |
| Abstraction | Minimal - direct endpoint calls | Protocol layer + plugin interface |
| State | Stateless - each request independent | Stateful session with MCP server |
| Coupling | Tightly coupled to Alpha Vantage API | Loosely coupled via plugin interface |
| Swapping providers | Requires code changes | Just swap plugin implementation |
| Complexity | Simple, straightforward | More setup, but more flexible |
| Best for | Single data source, simple needs | Multiple providers, modular architecture |
Visit Alpha Vantage and get a free API key.
Using uv (recommended):
uv pip install -r requirements.txtOr with pip:
pip install -r requirements.txtexport ALPHA_VANTAGE_API_KEY=your_api_key_hereOr create a .env file (copy from .env.example):
cp .env.example .env
# Edit .env and add your API keyuv run rest_example/main.py IBMOr without uv:
cd rest_example
python main.py IBMThis will:
- Make a direct HTTP GET request to Alpha Vantage API
- Parse the JSON response
- Display the stock quote
uv run mcp_example/main.py IBMOr without uv:
cd mcp_example
python main.py IBMThis will:
- Connect to the Alpha Vantage MCP server via http
- Call the
get_quotetool through MCP protocol - Display the same stock quote data
Both examples produce similar output:
Stock Quote - REST API
==================================================
Symbol: IBM
Price: $178.25
Change: +2.15 (+1.22%)
Volume: 45123456
Latest Trading Day: 2026-06-04
==================================================
Try various stock symbols:
uv run rest_example/main.py MSFT # Microsoft
uv run rest_example/main.py GOOGL # Google
uv run rest_example/main.py TSLA # Tesla
uv run mcp_example/main.py MSFT # Same symbols via MCP
uv run mcp_example/main.py GOOGL
uv run mcp_example/main.py TSLA# Direct HTTP call
response = requests.get(
"https://www.alphavantage.co/query",
params={'function': 'GLOBAL_QUOTE', 'symbol': symbol, 'apikey': api_key}
)
data = response.json()# MCP protocol call
result = await self.session.call_tool(
"get_quote",
arguments={"symbol": symbol}
)class StockDataPlugin(ABC):
@abstractmethod
def get_quote(self, symbol: str) -> Dict:
passThis interface makes it trivial to add other MCP stock servers:
FinnhubMCPPluginPolygonMCPPluginYahooFinanceMCPPlugin
Just implement the StockDataPlugin interface and swap it in main.py.
Both examples handle common errors:
- Missing API key
- Invalid stock symbol
- Network failures
- API rate limits (free tier: 25 requests/day)
- REST is simpler for single-source integrations - less boilerplate, direct control
- MCP provides abstraction that shines when you need to support multiple data sources
- Plugin pattern (in MCP example) makes swapping providers trivial without changing client code
- Protocol layer adds overhead but provides standardization and future flexibility
- Both approaches can achieve the same result - choose based on your needs
To extend this project:
- Add more MCP plugins (Finnhub, Polygon, etc.)
- Implement historical data fetching
- Add caching layer
- Create a unified CLI that switches between REST and MCP
- Build a web UI that uses both backends
This is a learning project - use freely for educational purposes.
