A high-performance financial data MCP server in Go for your LLMs.
This repository implements a Model Context Protocol (MCP) server in Go,
using the official github.com/modelcontextprotocol/go-sdk package. It focuses
on server-side aggregation of stock price data so your LLM can request
pre-computed metrics (VWAP, SMA, highs, lows, volume) instead of pulling and
processing raw ticks itself.
- Official MCP Go SDK: Built on
github.com/modelcontextprotocol/go-sdk. - Financial data source: Fetches OHLCV data from Yahoo Finance's public chart API.
- Server-side aggregation:
- Volume-weighted average price (VWAP)
- Annualized volatility and z-score for threshold reasoning
- Trailing simple moving average (SMA) over a configurable window
- High/low, last close, total volume
- Structured response: Metrics, context (regime, data quality, market open), metadata, and an interpretation hint for LLM reasoning.
- News & sentiment (optional): When
ALPHA_VANTAGE_API_KEYis set, responses include recent market news and sentiment for the symbol via Alpha Vantage’s News & Sentiment API. - Single MCP tool:
aggregate_market_data: fetch and aggregate historical prices for a symbol (and optional news/sentiment).
git clone <this-repo-url> markets-mcp
cd markets-mcp
go mod tidy
go build ./...The server is implemented as a stdin/stdout MCP server binary:
go build -o markets-mcp ./cmd/markets-mcp
./markets-mcpIn an MCP-compatible client (e.g. an IDE or agent framework that supports MCP),
configure a command-based server pointing to the built markets-mcp binary.
Optional: Alpha Vantage API key (for news & sentiment)
To include market news and sentiment in aggregate_market_data responses, set the environment variable ALPHA_VANTAGE_API_KEY to your API key (get one at alphavantage.co/support/#api-key). If unset, the response omits the news_sentiment block.
Name: aggregate_market_data
Description: Fetch and aggregate historical stock price data (VWAP, SMA,
highs, lows, volume) and latest news sentiments for a given symbol.
Input schema:
symbol(string, required): ticker symbol, e.g.AAPL,MSFT.range(string, optional): time range for the query, e.g.1d,5d,1mo,3mo,6mo,1y,5y,max. Defaults to1mo.interval(string, optional): sampling interval, e.g.1m,5m,15m,1d,1wk,1mo. Defaults to1d.window(integer, optional): trailing window size (in data points) used for the simple moving average. Defaults to20.
Response structure
The tool returns a JSON object with the following top-level fields:
| Field | Type | Meaning |
|---|---|---|
symbol |
string | Ticker symbol that was queried (e.g. AAPL). |
metrics |
object | Numerical series metrics; see Metrics below. |
context |
object | Regime, data quality, and session info; see Context below. |
interpretation_hint |
string | One-line summary to help reason about thresholds (e.g. “Price is currently trading above VWAP on average volume…”). |
metadata |
object | Series boundaries and request parameters for reproducibility; see Metadata below. |
news_sentiment |
object (optional) | When ALPHA_VANTAGE_API_KEY is set, recent market news and sentiment for the symbol; see News & Sentiment below. Omitted if no key or fetch fails. |
Metrics (metrics)
| Field | Type | Meaning |
|---|---|---|
vwap |
number | Volume-weighted average price over the full series. |
volatility_ann |
number | Annualized volatility from daily log returns (e.g. 0.22 = 22%). Useful for risk/threshold reasoning. |
z_score |
number | (last_close - vwap) / std(closes). > 0: price above VWAP; < 0: below. Roughly >1 or <-1 = notable deviation. |
sma |
number | Trailing simple moving average of close over the requested window (last N points). |
high |
number | Highest high price in the series. |
low |
number | Lowest low price in the series. |
last_close |
number | Most recent close price in the series. |
total_volume |
number | Sum of volume over all points in the series. |
Context (context)
| Field | Type | Meaning |
|---|---|---|
regime |
string | trending_up, trending_down, or sideways, derived from last close vs SMA and recent price trend. |
data_quality |
string | high (≥20 points), medium (≥10), or low — indicates reliability of the series. |
is_market_open |
boolean | Whether the US equity market (NYSE/NASDAQ) is currently in regular session (14:30–21:00 UTC). |
retrieved_at |
string | RFC3339 UTC timestamp when the data/signal was fetched (when the tool ran). |
data_source |
string | Provider of the price data (e.g. Yahoo Finance) for source transparency. |
Metadata (metadata)
| Field | Type | Meaning |
|---|---|---|
range |
string | Time range used for the query (e.g. 5d, 1mo). |
interval |
string | Sampling interval (e.g. 1d, 1wk). |
count |
number | Number of data points in the series. |
start |
string | RFC3339 timestamp of the first point. |
end |
string | RFC3339 timestamp of the last point. |
window |
number | Window size (in points) used for the SMA. |
News & Sentiment (news_sentiment)
Present only when Alpha Vantage API key is configured. The server aggregates all returned articles into a single weighted score and exposes only the top 3 most impactful articles:
| Field | Type | Meaning |
|---|---|---|
source |
string | Data provider (e.g. Alpha Vantage). |
weighted_score |
number | Relevance-weighted sentiment score across all fetched articles. Uses relevance_score × sentiment, falling back to overall article sentiment when ticker-specific is missing. |
weighted_label |
string | Label derived from weighted_score using Alpha Vantage thresholds (Bearish, Somewhat-Bearish, Neutral, Somewhat-Bullish, Bullish). |
feed |
array | Top 3 most impactful articles, sorted by `relevance_score × |
feed[].title |
string | Headline. |
feed[].url |
string | Article URL. |
feed[].time_published |
string | Publication time (API format). |
feed[].summary |
string | Short summary. |
feed[].overall_sentiment_score |
number | Article-level sentiment score. |
feed[].overall_sentiment_label |
string | e.g. Bearish, Neutral, Bullish. |
feed[].relevance_score |
number | Relevance to the ticker (0–1). |
feed[].ticker_sentiment_score |
number | Ticker-specific sentiment (e.g. ≤ -0.35 Bearish, ≥ 0.35 Bullish). |
feed[].ticker_sentiment_label |
string | e.g. Somewhat-Bullish, Neutral. |
Example response
{
"symbol": "AAPL",
"metrics": {
"vwap": 260.72,
"volatility_ann": 0.22,
"z_score": 1.12,
"sma": 258.5,
"high": 275.0,
"low": 248.0,
"last_close": 262.0,
"total_volume": 125000000
},
"context": {
"regime": "trending_up",
"data_quality": "high",
"is_market_open": false,
"retrieved_at": "2025-03-09T14:30:00Z",
"data_source": "Yahoo Finance"
},
"interpretation_hint": "Price is currently trading above VWAP (z=1.12) on average volume; annualized volatility 22%. Regime: trending_up. Data quality: high.",
"metadata": {
"range": "6mo",
"interval": "1d",
"count": 126,
"start": "2024-09-10T00:00:00Z",
"end": "2025-03-09T00:00:00Z",
"window": 20
},
"news_sentiment": {
"source": "Alpha Vantage",
"weighted_score": 0.21,
"weighted_label": "Somewhat-Bullish",
"feed": [
{
"title": "Apple announces new product line",
"url": "https://example.com/article",
"time_published": "20250309T120000",
"summary": "Summary text.",
"overall_sentiment_score": 0.15,
"overall_sentiment_label": "Neutral",
"relevance_score": 0.8,
"ticker_sentiment_score": 0.22,
"ticker_sentiment_label": "Somewhat-Bullish"
}
]
}
}The exact configuration depends on your MCP client. Conceptually, you would invoke the tool with arguments like:
{
"name": "aggregate_market_data",
"arguments": {
"symbol": "AAPL",
"range": "6mo",
"interval": "1d",
"window": 50
}
}The response will contain the aggregated metrics in structured JSON as described above, ready for your LLM to consume.